diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 816bbe98..c83a6dcd 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,6 +1,6 @@ # 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 the agent's actual identity in Pascal-Case for `sourceType` and the session ID prefix. Do not use inaccurate aliases, lowercase names, or legacy placeholders. Example: `Codex`. For specific operational instructions (session bootstrap, turn logging lifecycle, helper command order), follow `AGENTS-README-FIRST.yaml`. ## Response Formatting diff --git a/.github/workflows/mcp-server-ci.yml b/.github/workflows/mcp-server-ci.yml index 82f7ec0c..afe31422 100644 --- a/.github/workflows/mcp-server-ci.yml +++ b/.github/workflows/mcp-server-ci.yml @@ -30,7 +30,6 @@ on: - "scripts/Start-McpServer.ps1" - "scripts/Package-McpServerMsix.ps1" - "scripts/Migrate-McpTodoStorage.ps1" - - "scripts/Validate-McpConfig.ps1" - "scripts/Test-McpMultiInstance.ps1" - ".github/workflows/mcp-server-ci.yml" - "GitVersion.yml" @@ -55,7 +54,6 @@ on: - "scripts/Start-McpServer.ps1" - "scripts/Package-McpServerMsix.ps1" - "scripts/Migrate-McpTodoStorage.ps1" - - "scripts/Validate-McpConfig.ps1" - "scripts/Test-McpMultiInstance.ps1" - ".github/workflows/mcp-server-ci.yml" - "GitVersion.yml" @@ -78,10 +76,6 @@ jobs: - name: Restore run: dotnet restore tests/McpServer.Support.Mcp.Tests/McpServer.Support.Mcp.Tests.csproj - - name: Validate MCP config - shell: pwsh - run: ./scripts/Validate-McpConfig.ps1 - - name: Build run: dotnet build tests/McpServer.Support.Mcp.Tests/McpServer.Support.Mcp.Tests.csproj -c Release --no-restore @@ -128,6 +122,7 @@ jobs: windows-msix: runs-on: windows-latest needs: build-test-publish + continue-on-error: true steps: - uses: actions/checkout@v4 @@ -147,63 +142,10 @@ jobs: name: mcp-server-msix path: artifacts/msix/*.msix - multi-instance-smoke: - runs-on: windows-latest - needs: build-test-publish - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - global-json-file: global.json - - - name: Run multi-instance smoke test - shell: pwsh - run: | - ./scripts/Test-McpMultiInstance.ps1 -Configuration Staging -FirstInstance default -SecondInstance alt-local -TimeoutSeconds 180 - - docker-smoke: + release-main: runs-on: ubuntu-latest - needs: build-test-publish - steps: - - uses: actions/checkout@v4 - - - name: Build Docker image - run: docker build -t mcp-server:ci . - - - name: Start container and health check - run: | - docker run -d --name mcp-ci -p 7147:7147 \ - -e Mcp__Port=7147 \ - -e Mcp__DataDirectory=/data \ - -e VectorIndex__IndexPath=/data/vector.idx \ - -e Embedding__Enabled=false \ - -e VectorIndex__Enabled=false \ - mcp-server:ci - for i in {1..30}; do - if curl -fsS http://localhost:7147/health; then - echo "Health check passed" - break - fi - sleep 1 - done - curl -fsS http://localhost:7147/health | grep -q Healthy - - - name: Test TODO endpoint - run: curl -fsS http://localhost:7147/mcpserver/todo | head -c 200 - - - name: Test Swagger - run: curl -fsS http://localhost:7147/swagger/v1/swagger.json -o /dev/null - - - name: Cleanup - if: always() - run: docker stop mcp-ci && docker rm mcp-ci || true - - release-main: - runs-on: ubuntu-latest - needs: [windows-msix, multi-instance-smoke, docker-smoke] - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: [windows-msix] + if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.windows-msix.result == 'success' steps: - name: Download MSIX artifact uses: actions/download-artifact@v4 diff --git a/.gitignore b/.gitignore index 5a8312ad..5173e41a 100644 --- a/.gitignore +++ b/.gitignore @@ -358,6 +358,9 @@ ASALocalRun/ # MSBuild Binary and Structured Log *.binlog +# Build output +**/bin/ + # NVidia Nsight GPU debugger configuration file *.nvuser @@ -486,6 +489,7 @@ $RECYCLE.BIN/ # MCP server marker files (runtime artifacts for agent port discovery) .mcp-server.yaml .mcp-server.json +.mcpServer/ # SQLite database files (runtime data) *.db @@ -505,3 +509,5 @@ AGENTS-README-FIRST.yaml # MCP Data mcp-data/ +/src/McpServer.Support.Mcp/Properties/launchSettings.json +/src/McpServer.AgentFramework.SampleHost/Properties/launchSettings.json diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index dd48b4a5..3f36f8d7 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -7,6 +7,7 @@ config: MD032: false MD033: false MD034: false + MD038: false MD040: false MD042: false MD060: false diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..97af5cfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "fusion-360-helper.enabled": false +} diff --git a/AGENTS.md b/AGENTS.md index 2f699fdc..cde17b47 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,26 +1,27 @@ # Agent Instructions -## 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`. +## 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. +10. When writing session logs or other audit records, agents must identify themselves accurately using their real agent identity in Pascal-Case. Do not use placeholder, legacy, or misleading sourceType values. ## Where Things Live @@ -29,6 +30,9 @@ On every subsequent user message: - `docs/context/` — on-demand reference docs (schemas, module docs, compliance rules, action types) - `docs/Project/` — requirements docs, TODO.yaml, mapping matrices - `templates/` — prompt templates (loaded on demand) +- `tools/powershell/McpContext.psm1` — PowerShell module for context ingestion/query workflows +- `tools/powershell/McpContext.USER.md` — user-level guide for the McpContext module +- `tools/powershell/McpContext.AGENT.md` — agent workflow instructions for the McpContext module ## Context Loading by Task Type @@ -72,9 +76,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 turn'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 @@ -86,31 +90,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 turn'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 item 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. 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. +## 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 @@ -127,4 +131,3 @@ At regular intervals during long sessions (~10 interactions): - Do not use table-style output in responses. - Use concise bullets or short paragraphs instead. - diff --git a/Directory.Packages.props b/Directory.Packages.props index 474c4264..ca4c891a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,10 +7,12 @@ + + @@ -26,6 +28,12 @@ + + + + + + @@ -43,6 +51,10 @@ + + + + @@ -50,6 +62,7 @@ + @@ -62,7 +75,6 @@ - diff --git a/GitVersion.yml b/GitVersion.yml index cf82d828..bdd2201c 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,5 +1,5 @@ mode: ContinuousDelivery -next-version: 0.2.59 +next-version: 0.2.74 assembly-versioning-scheme: MajorMinorPatch assembly-informational-format: '{SemVer}+Branch.{BranchName}.Sha.{ShortSha}' branches: diff --git a/McpServer.sln b/McpServer.sln index d32da1ed..c78805d6 100644 --- a/McpServer.sln +++ b/McpServer.sln @@ -51,6 +51,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.ToolRegistry.Vali EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.Workspace.Validation", "tests\McpServer.Workspace.Validation\McpServer.Workspace.Validation.csproj", "{1255D16B-B9CC-4647-A567-C6ABCA1E166E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.McpAgent", "src\McpServer.McpAgent\McpServer.McpAgent.csproj", "{16649839-FA22-438C-B554-5AC585BE749E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.McpAgent.SampleHost", "src\McpServer.McpAgent.SampleHost\McpServer.McpAgent.SampleHost.csproj", "{2280A17E-2C01-407F-87FC-2AC59C760CC4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.McpAgent.Tests", "tests\McpServer.McpAgent.Tests\McpServer.McpAgent.Tests.csproj", "{74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -325,6 +331,42 @@ Global {1255D16B-B9CC-4647-A567-C6ABCA1E166E}.Release|x64.Build.0 = Release|x64 {1255D16B-B9CC-4647-A567-C6ABCA1E166E}.Release|x86.ActiveCfg = Release|x86 {1255D16B-B9CC-4647-A567-C6ABCA1E166E}.Release|x86.Build.0 = Release|x86 + {16649839-FA22-438C-B554-5AC585BE749E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {16649839-FA22-438C-B554-5AC585BE749E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16649839-FA22-438C-B554-5AC585BE749E}.Debug|x64.ActiveCfg = Debug|x64 + {16649839-FA22-438C-B554-5AC585BE749E}.Debug|x64.Build.0 = Debug|x64 + {16649839-FA22-438C-B554-5AC585BE749E}.Debug|x86.ActiveCfg = Debug|x86 + {16649839-FA22-438C-B554-5AC585BE749E}.Debug|x86.Build.0 = Debug|x86 + {16649839-FA22-438C-B554-5AC585BE749E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {16649839-FA22-438C-B554-5AC585BE749E}.Release|Any CPU.Build.0 = Release|Any CPU + {16649839-FA22-438C-B554-5AC585BE749E}.Release|x64.ActiveCfg = Release|x64 + {16649839-FA22-438C-B554-5AC585BE749E}.Release|x64.Build.0 = Release|x64 + {16649839-FA22-438C-B554-5AC585BE749E}.Release|x86.ActiveCfg = Release|x86 + {16649839-FA22-438C-B554-5AC585BE749E}.Release|x86.Build.0 = Release|x86 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Debug|x64.ActiveCfg = Debug|x64 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Debug|x64.Build.0 = Debug|x64 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Debug|x86.ActiveCfg = Debug|x86 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Debug|x86.Build.0 = Debug|x86 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Release|Any CPU.Build.0 = Release|Any CPU + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Release|x64.ActiveCfg = Release|x64 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Release|x64.Build.0 = Release|x64 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Release|x86.ActiveCfg = Release|x86 + {2280A17E-2C01-407F-87FC-2AC59C760CC4}.Release|x86.Build.0 = Release|x86 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Debug|x64.ActiveCfg = Debug|x64 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Debug|x64.Build.0 = Debug|x64 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Debug|x86.ActiveCfg = Debug|x86 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Debug|x86.Build.0 = Debug|x86 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Release|Any CPU.Build.0 = Release|Any CPU + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Release|x64.ActiveCfg = Release|x64 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Release|x64.Build.0 = Release|x64 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Release|x86.ActiveCfg = Release|x86 + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -352,5 +394,8 @@ Global {47A07688-1499-4823-902A-98BC07077B05} = {75E852DF-4CB3-4318-9A92-82F84CD3DFA7} {0D95192B-7884-4762-9777-0B7C030A02CE} = {75E852DF-4CB3-4318-9A92-82F84CD3DFA7} {1255D16B-B9CC-4647-A567-C6ABCA1E166E} = {75E852DF-4CB3-4318-9A92-82F84CD3DFA7} + {16649839-FA22-438C-B554-5AC585BE749E} = {ACFF16D9-C460-4DAF-8806-E9FD58069B7B} + {2280A17E-2C01-407F-87FC-2AC59C760CC4} = {ACFF16D9-C460-4DAF-8806-E9FD58069B7B} + {74ED711C-8F0A-4C78-9B96-FC8EAAA1E2BD} = {75E852DF-4CB3-4318-9A92-82F84CD3DFA7} EndGlobalSection EndGlobal diff --git a/README.md b/README.md index a0ddb907..3569802c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # MCP Server -Standalone repository for `McpServer.Support.Mcp`, the MCP context server used for todo management, session logs, context search, repository operations, and GitHub issue sync. +MCP Server is a standalone ASP.NET Core service for workspace-scoped context retrieval, TODO orchestration, session logging, repository operations, GraphRAG, and GitHub automation. -## What This Server Provides +## Documentation - HTTP API with Swagger UI - MCP over STDIO transport (`--transport stdio`) @@ -234,12 +234,12 @@ Pipeline jobs include: ## VS Code / VS 2026 Extensions -Extension sources and packaging scripts live in: +Extension sources live in: - `extensions/fwh-mcp-todo` (legacy name) - `extensions/McpServer-mcp-todo` -- `scripts/Package-Vsix.ps1` -- `scripts/Build-AndInstall-Vsix.ps1` + +In the RequestTracker host workspace, VSIX packaging is orchestrated by the repo-root `BuildAndInstallVsix` target rather than standalone scripts inside this submodule. ## Client Library @@ -270,6 +270,8 @@ Source: `src/McpServer.Client/` — see the [package README](#) for full usage. ## Additional Documentation -- Full server guide: `docs/MCP-SERVER.md` - User documentation: `docs/USER-GUIDE.md` +- Server and operator guide: `docs/MCP-SERVER.md` - Documentation index: `docs/README.md` +- FAQ: `docs/FAQ.md` +- Client integration: `docs/CLIENT-INTEGRATION.md` diff --git a/appsettings.Staging.yaml b/appsettings.Staging.yaml index 9c9623d4..c14e2987 100644 --- a/appsettings.Staging.yaml +++ b/appsettings.Staging.yaml @@ -10,6 +10,10 @@ Serilog: Microsoft.AspNetCore: Warning McpServer.Support.Mcp.Logging: Verbose +VoiceConversation: + DefaultExecutionStrategy: copilot-cli + ModelApiKeyEnvironmentVariableName: OPENAI_API_KEY + Mcp: Port: 7147 DataSource: mcp.db @@ -17,7 +21,7 @@ Mcp: RepoRoot: "." TodoFilePath: docs/Project/TODO.yaml TodoStorage: - Provider: yaml + Provider: sqlite SqliteDataSource: mcp.db Workspaces: - WorkspacePath: E:\github\McpServer @@ -33,7 +37,7 @@ Mcp: RepoRoot: "." TodoFilePath: docs/Project/TODO.yaml TodoStorage: - Provider: yaml + Provider: sqlite SqliteDataSource: mcp.db alt-local: Port: 7157 diff --git a/appsettings.yaml b/appsettings.yaml index 29766ed3..afc6f89b 100644 --- a/appsettings.yaml +++ b/appsettings.yaml @@ -2,22 +2,21 @@ Logging: LogLevel: Default: Information Microsoft.AspNetCore: Warning - Serilog: MinimumLevel: Default: Information Override: Microsoft.AspNetCore: Warning McpServer.Support.Mcp.Logging: Verbose - -AllowedHosts: "*" - +AllowedHosts: '*' +VoiceConversation: + DefaultExecutionStrategy: copilot-cli + ModelApiKeyEnvironmentVariableName: OPENAI_API_KEY Embedding: Enabled: true Dimensions: 384 MaxSequenceLength: 128 AutoDownload: true - VectorIndex: Enabled: true Dimensions: 384 @@ -26,57 +25,82 @@ VectorIndex: EfConstruction: 200 EfSearch: 50 IndexPath: mcp-data/vector.idx - Mcp: Port: 7147 DataSource: mcp.db - DataDirectory: "." - RepoRoot: "." + DataDirectory: . + RepoRoot: . TodoFilePath: docs/Project/TODO.yaml SessionsPath: docs/sessions UnifiedModelSchemaPath: docs/schemas/UnifiedModel.schema.json ExternalDocsPath: docs/external TodoStorage: - Provider: yaml + Provider: sqlite SqliteDataSource: mcp.db + DesktopLaunch: + Enabled: false + AccessToken: '' + AllowedExecutables: [] Workspaces: - - WorkspacePath: E:\github\McpServer - Name: McpServer - TodoPath: docs/Project/TODO.yaml - DateTimeCreated: "2026-02-21T00:00:00+00:00" - DateTimeModified: "2026-02-23T00:00:00+00:00" + - WorkspacePath: E:\github\McpServer + Name: McpServer + TodoPath: docs/Project/TODO.yaml + IsPrimary: false + IsEnabled: true + DateTimeCreated: &o0 + DateTime: 0001-01-01T00:00:00.0000000 + UtcDateTime: 0001-01-01T00:00:00.0000000Z + LocalDateTime: 0001-01-01T00:00:00.0000000-06:00 + Date: 0001-01-01T00:00:00.0000000 + Day: 1 + DayOfWeek: Monday + DayOfYear: 1 + Hour: 0 + Millisecond: 0 + Microsecond: 0 + Nanosecond: 0 + Minute: 0 + Month: 1 + Offset: 00:00:00 + TotalOffsetMinutes: 0 + Second: 0 + Ticks: 0 + UtcTicks: 0 + TimeOfDay: 00:00:00 + Year: 1 + DateTimeModified: *o0 Instances: default: Port: 7147 DataSource: mcp.db - DataDirectory: "." - RepoRoot: "." + DataDirectory: . + RepoRoot: . TodoFilePath: docs/Project/TODO.yaml TodoStorage: - Provider: yaml + Provider: sqlite SqliteDataSource: mcp.db alt-local: Port: 7157 DataSource: mcp-alt.db - DataDirectory: "." + DataDirectory: . RepoRoot: docs TodoFilePath: docs/Project/TODO.yaml TodoStorage: Provider: sqlite SqliteDataSource: mcp-alt.db InteractionLogging: - LoggingServiceUrl: "" + LoggingServiceUrl: '' QueueCapacity: 1000 IncludeQueryString: false Parseable: Url: http://localhost:8000 IngestUrl: http://localhost:8000/api/v1/ingest StreamName: mcp - Username: admin - Password: admin + Username: '' + Password: '' FallbackLogPath: logs/mcp-.log Auth: Authority: http://localhost:7080/realms/mcpserver Audience: mcp-server-api - ClientSecret: "" + ClientSecret: '' RequireHttpsMetadata: false diff --git a/docs/CLIENT-INTEGRATION.md b/docs/CLIENT-INTEGRATION.md index ab287dc9..d33cf73f 100644 --- a/docs/CLIENT-INTEGRATION.md +++ b/docs/CLIENT-INTEGRATION.md @@ -75,12 +75,13 @@ For MCP-compatible clients (e.g., Cursor), configure the STDIO transport: ### Available STDIO Tools -See `docs/stdio-tool-contract.json` for the complete machine-readable manifest of all 21 tools. +See `docs/stdio-tool-contract.json` for the complete machine-readable manifest of all 22 tools. Key tool categories: -- **Context**: `context_search`, `context_pack`, `context_sources` +- **Context**: `context_search`, `context_pack`, `context_sources`, `context_ingest_website` - **Repository**: `repo_read`, `repo_list`, `repo_write` +- **Desktop**: `desktop_launch` - **Sync**: `sync_run`, `sync_status` - **TODO**: `todo_list`, `todo_get`, `todo_create`, `todo_update`, `todo_delete` - **Session Logs**: `sessionlog_submit`, `sessionlog_query`, `sessionlog_dialog` @@ -105,18 +106,77 @@ var client = McpServerClientFactory.Create(new McpServerClientOptions { BaseUrl = new Uri("http://localhost:7147"), ApiKey = "token-from-marker", + DesktopLaunchToken = "desktop-launch-token-from-secure-config", WorkspacePath = @"E:\github\MyProject", }); // All requests include both X-Api-Key and X-Workspace-Path headers var todos = await client.Todo.QueryAsync(); +var launch = await client.Desktop.LaunchAsync(new DesktopLaunchRequest +{ + ExecutablePath = @"C:\Windows\System32\cmd.exe", + Arguments = "/c exit 0", + CreateNoWindow = true, + WaitForExit = true, +}); ``` +Remote desktop launch also requires the server-side `Mcp:DesktopLaunch:Enabled` feature gate, +the `Mcp:DesktopLaunch:AllowedExecutables` allowlist, and the privileged +`X-Desktop-Launch-Token` header supplied by `McpServerClientOptions.DesktopLaunchToken`. + Switch workspace at runtime: ```csharp client.WorkspacePath = @"E:\github\OtherProject"; ``` +Admin-only configuration endpoints are also available through the typed client when you supply an admin JWT bearer token: + +```csharp +client.BearerToken = adminJwt; +var values = await client.Configuration.GetValuesAsync(); + +var updated = await client.Configuration.PatchValuesAsync(new Dictionary +{ + ["VoiceConversation:CopilotModel"] = "gpt-5.4", + ["VoiceConversation:ModelApiKey"] = null, // remove the persisted key +}); +``` + +## Hosted .NET Agent Framework Library + +Use `src\McpServer.McpAgent` when you want a .NET 9 host application to consume MCP Server session-log, TODO, repository, desktop-launch, and in-process PowerShell workflows through Microsoft Agent Framework-oriented registration instead of hand-assembling transport glue. + +Typical registration: + +```csharp +services.AddMcpServerMcpAgent(options => +{ + options.BaseUrl = new Uri("http://localhost:7147"); + options.ApiKey = "token-from-marker"; + options.WorkspacePath = @"E:\github\MyProject"; + options.SourceType = "Codex"; +}); + +using var serviceProvider = services.BuildServiceProvider(); +var hostedAgentFactory = serviceProvider.GetRequiredService(); +var hostedAgent = hostedAgentFactory.CreateHostedAgent(); +var registration = hostedAgent.Registration; +``` + +Built-in hosted services include: + +- `ISessionLogWorkflow` for session bootstrap, turn lifecycle updates, and canonical session/request identifiers. +- `ITodoWorkflow` for TODO query/get/update plus buffered or streaming plan/status/implementation flows. +- built-in MCP tools for repository access, local desktop launch, and in-process PowerShell sessions (`mcp_repo_*`, `mcp_desktop_launch`, `mcp_powershell_session_*`). +- `IMcpHostedAgent` / `IMcpHostedAgentFactory` for creating `ChatClientAgent`-ready registrations and run options with the built-in MCP tool set attached, plus `IMcpHostedAgent.PowerShellSessions` for host-driven direct local PowerShell execution. + +Reference implementations: + +- Library source: `src\McpServer.McpAgent` +- Interactive preview host: `src\McpServer.McpAgent.SampleHost` +- Automated acceptance coverage: `tests\McpServer.McpAgent.Tests\HostedAgentWorkflowIntegrationTests.cs` + ## Health Check All clients should verify connectivity before making API calls: diff --git a/docs/FAQ.md b/docs/FAQ.md index ad4d5743..394a2515 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -79,9 +79,15 @@ Two backends are available, configured via `Mcp:TodoStorage:Provider`: | `yaml` (default) | `docs/Project/TODO.yaml` file | Human-readable, version-controlled | | `sqlite` | `mcp.db` SQLite database | High-volume, concurrent access | -### How are TODO IDs structured? - -IDs follow a `SECTION-NNN` pattern (e.g., `APP-001`, `SUPPORT-042`). GitHub-synced items use `ISSUE-{number}` (e.g., `ISSUE-17`). +### How are TODO IDs structured? + +Persisted TODO IDs follow one of two canonical forms: + +- `--###` for standard workspace TODOs (for example, `MCP-AUTH-001`) +- `ISSUE-{number}` for GitHub-backed TODOs (for example, `ISSUE-17`) + +Create requests may also use `ISSUE-NEW`. The server immediately creates a GitHub issue, determines the +issue number, and saves the TODO using the canonical `ISSUE-{number}` id. ### Can I sync TODOs with GitHub Issues? @@ -91,7 +97,10 @@ Yes. Bidirectional sync is available: - **TODO → GitHub**: `POST /mcpserver/gh/issues/sync/to-github` - **Single issue**: `POST /mcpserver/gh/issues/{number}/sync` -Synced items get `ISSUE-{number}` IDs. Status changes (done ↔ closed) propagate in both directions. +Synced items get `ISSUE-{number}` IDs. Status changes (done ↔ closed) propagate in both directions. +For existing `ISSUE-*` items, MCP TODO priority is authoritative and syncs to canonical GitHub labels such +as `priority: HIGH`. After the first sync, ISSUE descriptions remain unchanged and later TODO updates add a +GitHub issue comment summarizing the change set. --- diff --git a/docs/MCP-SERVER.md b/docs/MCP-SERVER.md index 56ac0378..2c2b517f 100644 --- a/docs/MCP-SERVER.md +++ b/docs/MCP-SERVER.md @@ -1,160 +1,88 @@ -# MCP Server Guide +# MCP Server -## Overview +Standalone repository for `McpServer.Support.Mcp`, the MCP context server used for todo management, session logs, context search, repository operations, and GitHub issue sync. -## Documentation +## What This Server Provides -- [User Documentation](USER-GUIDE.md) -- [Documentation Index](README.md) -`McpServer.Support.Mcp` is the local MCP context server for todo data, -session logs, context search, repo file operations, and GitHub issue sync. +- HTTP API with Swagger UI +- MCP over STDIO transport (`--transport stdio`) +- Single-port multi-tenant workspace hosting via `X-Workspace-Path` header +- Per-workspace todo storage backend (`yaml` file-backed or `sqlite` table-backed) +- Three-tier workspace resolution: header → API key reverse lookup → default +- Optional interaction logging and Parseable sink support -Supported transports: +## Repository Layout -- HTTP REST + Swagger -- STDIO MCP (`--transport stdio`) +- `src/McpServer.Support.Mcp` - server application +- `tests/McpServer.Support.Mcp.Tests` - unit/integration tests +- `MCP-SERVER.md` - detailed operational and configuration guide +- `scripts` - run, validate, test, migration, extension, and packaging scripts +- `.github/workflows/mcp-server-ci.yml` - CI pipeline (build/test/artifacts/MSIX/docs quality) + +## Prerequisites + +- .NET SDK from `global.json` +- PowerShell 7+ +- Windows SDK tools (`makeappx.exe`) for MSIX packaging +- Optional: GitHub CLI (`gh`) for GitHub issue endpoints ## Quick Start -Build and run: +1. Restore and build: ```powershell -.\scripts\Start-McpServer.ps1 -Configuration Staging +dotnet restore McpServer.sln +dotnet build McpServer.sln -c Staging ``` -Run a named instance from `appsettings`: +1. Run the default instance: ```powershell .\scripts\Start-McpServer.ps1 -Configuration Staging -Instance default ``` -Run in STDIO mode: +1. Open Swagger: -```powershell -dotnet run --project src\McpServer.Support.Mcp\McpServer.Support.Mcp.csproj ` - -c Staging -- --transport stdio --instance default +```text +http://localhost:7147/swagger ``` -## Configuration - -Primary section: `Mcp`. - -Common keys: - -- `Mcp:Port` -- `Mcp:DataSource` -- `Mcp:DataDirectory` -- `Mcp:RepoRoot` -- `Mcp:TodoFilePath` -- `Mcp:TodoStorage:Provider` (`yaml` or `sqlite`) -- `Mcp:TodoStorage:SqliteDataSource` -- `Mcp:SessionsPath` -- `Mcp:ExternalDocsPath` - -### Config Reference - -- `Mcp:Port` (default `7147`): HTTP port when `PORT` is not set. -- `Mcp:DataSource` (default `mcp.db`): main SQLite DB filename or path. -- `Mcp:DataDirectory` (default `.`): base directory for relative DB paths. -- `Mcp:RepoRoot` (default `.`): root folder for repo-aware operations. -- `Mcp:TodoFilePath` (default `docs/Project/TODO.yaml`): - YAML path relative to `RepoRoot` unless absolute. -- `Mcp:TodoStorage:Provider` (default `yaml`): - todo backend (`yaml` or `sqlite`). -- `Mcp:TodoStorage:SqliteDataSource` (default `mcp.db`): - SQLite path for `sqlite` todo backend. -- `Mcp:SessionsPath` (default `docs/sessions`): - session log folder under `RepoRoot`. -- `Mcp:UnifiedModelSchemaPath` - (default `docs/schemas/UnifiedModel.schema.json`): - schema file path. -- `Mcp:ExternalDocsPath` (default `docs/external`): - external-doc cache folder under `RepoRoot`. -- `Mcp:InteractionLogging:*`: request/response interaction logging controls. -- `Mcp:Parseable:*`: Parseable sink controls. -- `Mcp:Instances:{name}:*`: per-instance overrides (static, config-file-only instances). -- `Mcp:Workspaces`: dynamic workspace list managed via API (see [Workspaces](#workspaces)). - -Environment overrides: - -- `PORT` (highest-priority runtime port override) -- `MCP_INSTANCE` (instance selector when `--instance` is not passed) - -## Workspaces - -Workspaces are dynamic MCP instances tied to local project folders. They are stored in -`Mcp:Workspaces` inside the active `appsettings.json` (never in the database) and managed -entirely through the REST API — no manual config editing needed. +## Run Modes -Each workspace entry has: +### HTTP mode -| Field | Required | Description | -|-------|----------|-------------| -| `WorkspacePath` | ✅ | Absolute path to the project folder | -| `Name` | auto | Defaults to the last path segment | -| `WorkspacePort` | auto | Shared with host port | -| `TodoPath` | auto | Defaults to `docs/todo.yaml` within `WorkspacePath` | -| `TunnelProvider` | optional | `ngrok`, `cloudflare`, or `frp` | - -Create a workspace: - -```bash -curl -X POST http://localhost:7147/mcpserver/workspace \ - -H "Content-Type: application/json" \ - -d '{"workspacePath": "E:\\github\\MyProject"}' -``` - -The workspace is immediately accessible on the shared host port. Target it with the `X-Workspace-Path` header: - -```bash -curl http://localhost:7147/mcpserver/todo \ - -H "X-Api-Key: " \ - -H "X-Workspace-Path: E:\\github\\MyProject" +```powershell +dotnet run --project src\McpServer.Support.Mcp\McpServer.Support.Mcp.csproj -c Staging -- --instance default ``` -### Workspace Resolution - -All workspaces share a single port. Per-request workspace identity is resolved via a three-tier chain: - -1. **`X-Workspace-Path` header** — highest priority. Send the absolute workspace path. -2. **API key reverse lookup** — the `X-Api-Key` token maps back to its workspace. -3. **Default workspace** — falls back to the primary workspace from configuration. - -This eliminates per-workspace ports and simplifies agent connectivity. - -Workspace state is written to `{ContentRootPath}/appsettings.json` by the running process. -For the Windows service this is `C:\ProgramData\McpServer\appsettings.json`. - -## Production Deployment (Windows Service) - -`C:\ProgramData\McpServer\appsettings.json` is the canonical Windows service configuration. -Environment-specific appsettings files (such as `appsettings.Production.json`) are not used by -the Windows service and should not be relied on for runtime configuration. - -Update the service in-place (preserves `appsettings.json` and `*.db*` files): +### STDIO MCP mode ```powershell -gsudo .\scripts\Update-McpService.ps1 +dotnet run --project src\McpServer.Support.Mcp\McpServer.Support.Mcp.csproj -c Staging -- --transport stdio --instance default ``` -The script performs: stop → backup all `*.json`/`*.db*` → publish Debug build → copy binaries → -restore backup → start → health-check → archive backup to `%USERPROFILE%\McpServer-Backups\`. +## Configuration -## Diagnostic Endpoints (Debug / Staging only) +Primary config section: `Mcp`. -Available in Debug builds and `Staging` environment; excluded in Production Release builds. +Important keys: -| Method | Route | Returns | -|--------|-------|---------| -| `GET` | `/mcpserver/diagnostic/execution-path` | `{ processPath, baseDirectory }` | -| `GET` | `/mcpserver/diagnostic/appsettings-path` | `{ environmentName, contentRootPath, files[] }` | +- `Mcp:Port` +- `Mcp:RepoRoot` +- `Mcp:DataSource` +- `Mcp:TodoFilePath` +- `Mcp:TodoStorage:Provider` (`yaml` or `sqlite`) +- `Mcp:TodoStorage:SqliteDataSource` +- `Mcp:GraphRag:*` (GraphRAG enablement, query defaults, backend command, concurrency) +- `Mcp:Instances:{name}:*` (per-instance overrides) -Use these to verify which binary and which `appsettings.json` a running instance has loaded. +Environment overrides: -Use `Mcp:Instances:{name}` to define isolated instances with unique ports, -roots, and storage backends. +- `PORT` - highest-priority runtime port override +- `MCP_INSTANCE` - instance selection when `--instance` is not passed +- Do not keep Parseable, OAuth, or other runtime secrets in shared repo config. Inject them through environment variables, secure host configuration, or machine-local overrides. -Example: +### Example `Mcp:Instances` ```json { @@ -164,6 +92,7 @@ Example: "Port": 7147, "RepoRoot": ".", "DataSource": "mcp.db", + "TodoFilePath": "docs/Project/TODO.yaml", "TodoStorage": { "Provider": "yaml", "SqliteDataSource": "mcp.db" @@ -173,6 +102,7 @@ Example: "Port": 7157, "RepoRoot": "temp_test", "DataSource": "mcp-alt.db", + "TodoFilePath": "docs/Project/TODO.yaml", "TodoStorage": { "Provider": "sqlite", "SqliteDataSource": "mcp-alt.db" @@ -183,55 +113,103 @@ Example: } ``` -Selection: - -- CLI: `--instance ` -- ENV: `MCP_INSTANCE=` +## Multi-Instance and Storage Validation -Validation: - -- Duplicate instance ports are rejected at startup. -- Missing `RepoRoot` or non-numeric `Port` is rejected at startup. - -Run two servers concurrently: +Run two configured instances: ```powershell .\scripts\Start-McpServer.ps1 -Configuration Staging -Instance default .\scripts\Start-McpServer.ps1 -Configuration Staging -Instance alt-local ``` -Automated two-instance smoke test: +Smoke test both instances: + +```powershell +.\scripts\Test-McpMultiInstance.ps1 -Configuration Staging -FirstInstance default -SecondInstance alt-local +``` + +Migrate todo data between backends: ```powershell -.\scripts\Test-McpMultiInstance.ps1 -Configuration Staging ` - -FirstInstance default -SecondInstance alt-local +.\scripts\Migrate-McpTodoStorage.ps1 -SourceBaseUrl http://localhost:7147 -TargetBaseUrl http://localhost:7157 ``` -Expected endpoints: +## Common Scripts + +- `scripts/Start-McpServer.ps1` - build/run server with optional `-Instance` +- `scripts/Run-McpServer.ps1` - direct local run helper +- `scripts/Update-McpService.ps1` - stop, publish Debug build, restore config/data, restart, health-check Windows service +- `scripts/Validate-McpConfig.ps1` - config validation +- `scripts/Test-McpMultiInstance.ps1` - two-instance smoke test +- `scripts/Test-GraphRagSmoke.ps1` - GraphRAG status/index/query smoke validation +- `scripts/Migrate-McpTodoStorage.ps1` - todo backend migration +- `scripts/Package-McpServerMsix.ps1` - publish and package MSIX -- `default` -> `http://localhost:7147/swagger` -- `alt-local` -> `http://localhost:7157/swagger` +## GraphRAG -## Todo Storage Backends +GraphRAG is workspace-scoped and disabled by default. When enabled, it can enhance `/mcpserver/context/search` and is also exposed directly through: -Backends: +- `GET /mcpserver/graphrag/status` +- `POST /mcpserver/graphrag/index` +- `POST /mcpserver/graphrag/query` -- `yaml`: reads and writes configured `TodoFilePath` -- `sqlite`: stores todo items in SQLite (`todo_items` table) +Key behavior: -Backend is selected per instance via `Mcp:Instances:{name}:TodoStorage`. +- Per-workspace GraphRAG state under `Mcp:GraphRag:RootPath` +- Index locking per workspace (single active index job by default) +- Explicit status lifecycle fields (`state`, `activeJobId`, failure metadata, artifact version) +- Fallback to context search when GraphRAG is disabled, uninitialized, not indexed, or backend execution fails +- Do not store backend secrets in repo config; inject runtime secrets via environment or secure host configuration -Migrate between backends: +Example config: + +```json +{ + "Mcp": { + "GraphRag": { + "Enabled": true, + "EnhanceContextSearch": true, + "RootPath": "mcp-data/graphrag", + "DefaultQueryMode": "local", + "DefaultMaxChunks": 20, + "IndexTimeoutSeconds": 600, + "QueryTimeoutSeconds": 120, + "BackendCommand": "", + "BackendArgs": "{operation} --graphRoot {graphRoot} --workspace {workspacePath}", + "MaxConcurrentIndexJobsPerWorkspace": 1, + "ArtifactVersion": "v1" + } + } +} +``` + +### GraphRAG Observability + +Track these operational indicators during rollout: + +- Index duration (`lastIndexDurationMs`) and active job contention (`index_conflict`) +- Fallback rate (`fallbackUsed` and `fallbackReason`) per query mode +- Failure categories (`failureCode`) and backend stderr patterns +- Indexed corpus drift (`lastIndexedDocumentCount` vs expected input volume) + +### GraphRAG Rollout Checklist + +1. Keep `Mcp:GraphRag:Enabled=false` in shared defaults. +2. Enable GraphRAG in one pilot workspace and run `scripts/Test-GraphRagSmoke.ps1`. +3. Verify fallback rate and failure codes remain acceptable under real workload. +4. Expand enablement workspace-by-workspace. +5. Keep external backend optional; if unavailable, ensure fallback path remains healthy. + +## Build and Test ```powershell -.\scripts\Migrate-McpTodoStorage.ps1 ` - -SourceBaseUrl http://localhost:7147 ` - -TargetBaseUrl http://localhost:7157 +dotnet build McpServer.sln -c Staging +dotnet test tests\McpServer.Support.Mcp.Tests\McpServer.Support.Mcp.Tests.csproj -c Debug ``` ## API Surface -Primary controllers: +Main endpoints: - `/mcpserver/todo` - `/mcpserver/sessionlog` @@ -239,59 +217,62 @@ Primary controllers: - `/mcpserver/repo` - `/mcpserver/gh` - `/mcpserver/sync` - -Swagger: - +- `/health` - `/swagger` -## Operations Runbook +## CI/CD -Update service in-place: +Workflow: `.github/workflows/mcp-server-ci.yml` -```powershell -gsudo .\scripts\Update-McpService.ps1 -``` +Pipeline jobs include: -Health checks: +- restore/build/test +- config validation +- OpenAPI artifact generation +- publish artifact upload +- Windows MSIX packaging +- markdown lint and link checking for docs -1. Open `/swagger` and `/health`. -2. Test todo read/write with `/mcpserver/todo`. -3. Test context search with `/mcpserver/context/search`. -4. For GitHub integration, run `gh auth status` on the host. +## VS Code / VS 2026 Extensions -Log signals: +Extension sources and packaging scripts live in: -- Startup shows selected mode and configured sinks. -- Interaction logging middleware captures request/response metadata. +- `extensions/fwh-mcp-todo` (legacy name) +- `extensions/McpServer-mcp-todo` +- `scripts/Package-Vsix.ps1` +- `scripts/Build-AndInstall-Vsix.ps1` -## Troubleshooting +## Client Library -- Port already in use: - change `Mcp:Port` (or instance `Port`) or stop conflicting process. -- Wrong root folder: - verify `RepoRoot` on the selected instance. -- Todo not found: - - YAML: verify `TodoFilePath` exists relative to `RepoRoot`. - - SQLite: verify `SqliteDataSource` path and file permissions. -- STDIO tools unavailable: - ensure server started with `--transport stdio`. +A typed REST client is available as a NuGet package for consuming the MCP Server API: -## Build and CI +```powershell +dotnet add package SharpNinja.McpServer.Client +``` -Workflow: `.github/workflows/mcp-server-ci.yml`. +```csharp +// With DI +builder.Services.AddMcpServerClient(options => +{ + options.BaseUrl = new Uri("http://localhost:7147"); + options.ApiKey = "your-api-key"; // optional +}); -Pipeline responsibilities: +// Without DI +var client = McpServerClientFactory.Create(new McpServerClientOptions +{ + BaseUrl = new Uri("http://localhost:7147"), +}); +``` -- Restore, build, and test server + tests -- Publish build artifact -- Run markdown and link checks +Covers all API endpoints: Todo, Context, SessionLog, GitHub, Repo, Sync, Workspace, and Tools. -## Packaging (MSIX) +Source: `src/McpServer.Client/` — see the [package README](#) for full usage. -Script: +## Additional Documentation -- `scripts/Package-McpServerMsix.ps1` +- User documentation: `USER-GUIDE.md` +- Documentation index: `README.md` +- FAQ: `FAQ.md` -The script publishes output, writes a minimal Appx manifest, and creates an -`.msix` package with `makeappx.exe`. diff --git a/docs/Project/Functional-Requirements.md b/docs/Project/Functional-Requirements.md index 66c17658..32b6e38b 100644 --- a/docs/Project/Functional-Requirements.md +++ b/docs/Project/Functional-Requirements.md @@ -1,407 +1,485 @@ -# Functional Requirements (MCP Server) - -## FR-SUPPORT-010 MCP Context Unification - -Local MCP server providing context retrieval, TODO management, repository access, session logging, and ingestion capabilities for AI agent integration. - -**Covered by:** `ContextController`, `TodoController`, `RepoController`, `SessionLogController`, `McpServerMcpTools`, `McpDbContext`, `HybridSearchService`, `EmbeddingService`, `VectorIndexService`, `Fts5SearchService`, `RepoFileService`, `IngestionCoordinator` - -## FR-MCP-001 Configurable workspace root and paths - -The server shall support configurable `RepoRoot`, `TodoFilePath`, `DataDirectory`, and index paths. - -**Covered by:** `IngestionOptions`, `IOptions` - -## FR-MCP-002 TODO management API - -The server shall provide CRUD/query operations for TODO items over REST and STDIO. - -**Covered by:** `TodoController`, `TodoService`, `SqliteTodoService` - -## FR-MCP-003 Session log ingestion and query - -The server shall ingest session logs and support searchable queries. - -**Covered by:** `SessionLogController`, `SessionLogService` - -## FR-MCP-004 Hybrid context search - -The server shall support FTS and vector search over indexed content. - -**Covered by:** `HybridSearchService`, `Fts5SearchService`, `VectorIndexService`, `EmbeddingService` - -## FR-MCP-005 GitHub issue sync - -The server shall support GitHub issue lifecycle integration and ISSUE-* TODO synchronization. - -**Covered by:** `GitHubController`, `GitHubCliService`, `IssueTodoSyncService` - -## FR-MCP-006 Multi-source ingestion - -The server shall ingest repository files, session logs, external docs, and issue content. - -**Covered by:** `IngestionCoordinator`, `RepoIngestor`, `SessionLogIngestor`, `ExternalDocsIngestor`, `GitHubIngestor`, `IssueIngestor` - -## FR-MCP-007 Dual transport - -The server shall support HTTP and STDIO MCP transports. - -**Covered by:** `Program.cs`, `McpServerMcpTools`, `McpStdioHost` - -## FR-MCP-008 Containerized deployment - -The server shall support containerized deployment and packaged distribution. - -**Covered by:** `Dockerfile`, `docker-compose.mcp.yml` - -## FR-MCP-009 Workspace Management - -The server shall support dynamic workspace registration, configuration, and lifecycle management — replacing static instance configuration — with directory scaffolding and Base64URL-encoded path keys. All workspaces are served on a single port via `X-Workspace-Path` header resolution (see FR-MCP-043). - -**Covered by:** `WorkspaceController`, `WorkspaceService`, `WorkspaceConfigEntry` - -## FR-MCP-011 Workspace Process Orchestration - -The server shall manage workspace lifecycle via marker files: write `AGENTS-README-FIRST.yaml` on start, remove on stop. All workspaces share the single host process and port. Automatic startup of all registered workspaces writes markers on service start. - -**Covered by:** `WorkspaceProcessManager`, `IWorkspaceProcessManager`, `MarkerFileService` - -## FR-MCP-012 Tool Registry - -Agents shall be able to discover tools by keyword search across global and workspace-scoped tool definitions, and install tool definitions from GitHub-backed bucket repositories. - -**Covered by:** `ToolRegistryController`, `ToolRegistryService`, `ToolBucketService` - -## FR-MCP-013 Per-Workspace Auth Tokens - -The server shall protect all `/mcpserver/*` API endpoints with per-workspace cryptographic tokens that rotate on each service restart. Tokens are discoverable via the `AGENTS-README-FIRST.yaml` marker file, checked via the `X-Api-Key` header or `api_key` query parameter, and enforced by `WorkspaceAuthMiddleware`. Workspace resolution uses a three-tier chain: `X-Workspace-Path` header → API key reverse lookup → default workspace (see FR-MCP-043). - -**Covered by:** `WorkspaceAuthMiddleware`, `WorkspaceTokenService`, `WorkspaceResolutionMiddleware`, `MarkerFileService` - -## FR-MCP-014 Pairing Web UI - -*Moved to [Requirements-WebUI.md](Requirements-WebUI.md#fr-mcp-014-pairing-web-ui)* - -## FR-MCP-015 Tunnel Providers - -The server shall expose its HTTP interface to the internet via pluggable tunnel providers (ngrok, Cloudflare, FRP) configured through a strategy pattern and registered as hosted services. - -**Covered by:** `NgrokTunnelProvider`, `CloudflareTunnelProvider`, `FrpTunnelProvider` - -## FR-MCP-016 MCP Streamable HTTP Transport - -The server shall expose a native MCP protocol endpoint at `/mcp-transport` coexisting with the REST API on the same port, enabling standard MCP client connections via `ModelContextProtocol.AspNetCore`. - -**Covered by:** `Program.cs` (MapMcp), `ModelContextProtocol.AspNetCore` - -## FR-MCP-017 Windows Service - -The server shall run as a Windows service with automatic startup, failure recovery (restart on failure with 60 s delay), and PowerShell-based install/update/uninstall management. - -**Covered by:** `Program.cs` (UseWindowsService), `Manage-McpService.ps1` - -## FR-MCP-018 Marker File Agent Discovery - -When a workspace is started, the server shall write an `AGENTS-README-FIRST.yaml` marker file to the workspace root containing the shared host port, all endpoint paths, a machine-readable prompt, and PID. All markers point to the same port; workspace identity is resolved via the `X-Workspace-Path` header. The marker shall be removed when the workspace is stopped. - -**Covered by:** `MarkerFileService`, `WorkspaceProcessManager` - -## FR-MCP-019 Workspace Host Controller Isolation - -*Obsolete — replaced by single-app multi-tenant model (FR-MCP-043).* All controllers are available on the single host. Workspace lifecycle management endpoints on `WorkspaceController` remain admin-only. - -## FR-MCP-020 Workspace Auto-Start on Service Startup - -On service startup, the server shall automatically write marker files for all workspaces already registered, restoring agent discoverability without manual intervention. All workspaces share the single host port. - -**Covered by:** `WorkspaceProcessManager` (IHostedService.StartAsync) - -## FR-MCP-021 Workspace Auto-Init and Auto-Start on Creation - -When a new workspace is registered, the server shall automatically initialize the workspace directory scaffold (todo.yaml, mcp.db, docs structure) and write its marker file, so the workspace is immediately operational on the shared port. - -**Covered by:** `WorkspaceController` POST, `WorkspaceService.InitAsync` - -## FR-MCP-022 Tool Registry Default Bucket Seeding - -On first startup, the server shall seed default tool buckets from configuration (`Mcp:ToolRegistry:DefaultBuckets`) if they are not already registered, ensuring new installations have the primary tool repository available without manual setup. - -**Covered by:** `ToolRegistryOptions`, `Program.cs` - -## FR-MCP-023 AI-Assisted Requirements Analysis - -The server shall provide a requirements analysis capability that invokes the Copilot CLI to examine a TODO item's title, description, and technical details, identify matching existing FR/TR IDs from the project docs, create new FR/TR entries for unaddressed functionality, and persist the assigned IDs back to the TODO item. - -**Covered by:** `RequirementsService`, `IRequirementsService`, `ICopilotClient` - -## FR-MCP-024 Markdown Session Log Ingestion - -The ingestion pipeline shall parse legacy Markdown session log files (matching a `# Session Log – {title}` header pattern) into the unified session log schema alongside JSON session logs, enabling retroactive indexing of pre-existing agent session records. - -**Covered by:** `MarkdownSessionLogParser`, `SessionLogIngestor` - -## FR-MCP-025 Primary Workspace Detection and Deduplication - -One workspace is designated as the **primary** workspace — served by the host process directly with no child `WebApplication` spun up. Only a marker file is written. Resolution order: (1) first enabled workspace with `IsPrimary = true` and lowest port; (2) enabled workspace with lowest port if none marked primary; (3) no primary if no workspaces enabled. - -## FR-LOC-001 Localization Support - -Localization and internationalization support for the MCP server. *(Planned — implementation scope TBD.)* - -## FR-MCP-026 OIDC Authentication - -The server shall support standards-based OIDC JWT Bearer authentication for management endpoints using a configurable open-source .NET OIDC provider. Optional external identity federation (for example, GitHub) may be configured through that provider. Management endpoints (agent mutations) require JWT; read endpoints use existing API key auth. - -**Covered by:** `OidcAuthOptions`, `Program.cs`, `AgentController`, `Setup-McpKeycloak.ps1`, `setup-mcp-keycloak.sh` - -## FR-MCP-027 Agent Definition Management - -The server shall provide CRUD operations for agent type definitions with built-in defaults for well-known AI coding agents (copilot, cline, cursor, windsurf, claude-code, aider, continue). Built-in definitions are seeded on first run and cannot be deleted. - -**Covered by:** `AgentController`, `AgentService`, `AgentDefaults`, `AgentDefinitionEntity` - -## FR-MCP-028 Per-Workspace Agent Configuration - -The server shall support per-workspace agent configuration with overrides for launch command, models, branch strategy, seed prompt, and instruction files. Agent pool definitions shall also support intent-default flags (`IsInteractiveDefault`, `IsTodoPlanDefault`, `IsTodoStatusDefault`, `IsTodoImplementDefault`) used for fallback routing when a request does not specify an agent name. Agents can be banned per-workspace or globally with optional PR-gated unbanning. All agent lifecycle events (add, launch, exit, ban, unban, delete, merge, init) are logged for audit. - -**Covered by:** `AgentController`, `AgentService`, `AgentWorkspaceEntity`, `AgentEventLogEntity` - -## FR-MCP-029 CQRS Framework - -A standalone CQRS framework (`McpServer.Cqrs`) shall provide async command/query dispatch with a Result monad, decimal correlation IDs (`baseId.counter`), pipeline behaviors, and an `ILoggerProvider` implementation that auto-enriches structured logs with decomposed correlation context. The Dispatcher shall automatically log Result outcomes (success at Debug, errors at Error/Warning). - -**Status:** ✅ Complete - -**Covered by:** `McpServer.Cqrs` project (`Dispatcher`, `CallContext`, `CorrelationId`, `Result`, `IPipelineBehavior`), `McpServer.Cqrs.Mvvm` (IViewModelRegistry, ViewModelRegistryExtensions), `McpServer.UI.Core` (WorkspaceListViewModel, WorkspacePolicyViewModel, AddUiCore DI extension) - -**Implementation:** 37 unit tests passing. Provides `ICommand`/`IQuery` message types, `ICommandHandler<,>`/`IQueryHandler<,>` handlers, `Dispatcher` with pipeline behavior chain, `CallContext` with `CorrelationId` for structured logging, and `Result` monad with success/error paths. MVVM layer adds `IViewModelRegistry` for CLI exec command support. - -## FR-MCP-030 Director CLI - -*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-030-director-cli)* - -## FR-MCP-031 McpServer Management Web UI - -*Moved to [Requirements-WebUI.md](Requirements-WebUI.md#fr-mcp-031-mcpserver-management-web-ui)* - -## FR-MCP-032 Enhanced GitHub Integration - -Enhanced GitHub integration capabilities including GitHub federation through the configured OIDC provider for user authentication, and GitHub OAuth for agent workspace management and PR workflows. *(Planned — tracked as high-priority TODO.)* - -## FR-MCP-033 Natural Language Policy Management - -A Copilot-integrated prompt tool that accepts natural language policy directives (e.g. "Ban chinese sources from all workspaces") and translates them into workspace configuration changes across all or targeted workspaces. Each policy change is session-logged per affected workspace with action type `policy_change`. - -**Covered by:** `WorkspaceController` (`POST /mcpserver/workspace/policy`), `WorkspacePolicyService`, `WorkspacePolicyDirectiveParser`, `McpServerMcpTools.workspace_policy_apply` - -## FR-MCP-034 Workspace Compliance Configuration - -Per-workspace compliance configuration supporting four ban lists: `BannedLicenses` (SPDX identifiers), `BannedCountriesOfOrigin` (ISO 3166-1 alpha-2 codes), `BannedOrganizations`, and `BannedIndividuals`. Ban lists are conditionally rendered into the AGENTS-README-FIRST.yaml marker prompt via Handlebars templates. Agents must verify compliance before adding dependencies and log violations. - -**Covered by:** `WorkspaceDto`, `WorkspaceCreateRequest`, `WorkspaceUpdateRequest`, `MarkerFileService` - -## FR-MCP-035 Agent Values and Conduct Enforcement - -The marker prompt shall include mandatory sections for: absolute honesty, correctness above speed, complete decision documentation, professional representation and audit trail (commits, PRs, issues logged in full), and source attribution (web references logged). These are non-configurable and always present. - -**Covered by:** `templates/prompt-templates.yaml` (default-marker-prompt) - -## FR-MCP-036 Audited Copilot Interactions - -Every server-initiated Copilot interaction must be session-logged in every affected workspace. An `AuditedCopilotClient` decorator wraps `ICopilotClient` to create session log entries before and after each call, with action type `copilot_invocation`. - -**Covered by:** `AuditedCopilotClient`, `Program.cs` DI registration, `McpStdioHost` DI registration, `CopilotServiceCollectionExtensions` - -## FR-MCP-037 Director CLI Exec Command - -*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-037-director-cli-exec-command)* - -## FR-MCP-038 Session Continuity Protocol - -Agents must follow a session continuity protocol: at session start, read the marker file, query recent session logs (limit=5), query current TODOs, and read Requirements-Matrix.md. During long sessions, post updated session logs every ~10 interactions. Requirements and design decisions must be captured as they emerge, not deferred. - -**Covered by:** `templates/prompt-templates.yaml` (default-marker-prompt) - -## FR-MCP-039 MCP Context Indexing for New Projects - -All source files from `McpServer.Cqrs`, `McpServer.Cqrs.Mvvm`, `McpServer.UI.Core`, and `McpServer.Director` shall be indexed into the MCP context store for semantic search. The marker prompt lists these projects in the Available Capabilities section. - -**Covered by:** `Program.cs` / `McpStdioHost` `PostConfigure` allowlist merge, `appsettings.yaml` `Mcp:RepoAllowlist`, `templates/prompt-templates.yaml` (default-marker-prompt) - -## FR-MCP-040 Requirements Document CRUD Management - -The server shall support CRUD operations for Functional Requirements (FR), Technical Requirements (TR), Testing Requirements (TEST), and FR-to-TR mapping rows backed by the canonical project requirements Markdown files. - -**Covered by:** `RequirementsController`, `RequirementsDocumentService`, `IRequirementsRepository` - -## FR-MCP-041 Requirements Document Generation - -The server shall expose a requirements document generation endpoint that renders any canonical requirements document as Markdown and can return all documents together as a ZIP archive with canonical filenames. - -**Covered by:** `RequirementsController` (`/mcpserver/requirements/generate`), `RequirementsDocumentService`, `RequirementsDocumentRenderer` - -## FR-MCP-042 Requirements Management MCP Tools - -The STDIO MCP tool surface shall expose requirements management tools for listing, generating, creating, updating, and deleting requirements entries so AI agents can manage requirements directly from a conversation. - -**Covered by:** `FwhMcpTools` (`requirements_list`, `requirements_generate`, `requirements_create`, `requirements_update`, `requirements_delete`), `RequirementsDocumentService` - -## FR-MCP-043 Multi-Tenant Workspace Resolution - -The server shall resolve the target workspace per-request using a three-tier resolution chain: (1) `X-Workspace-Path` header (highest priority), (2) API key reverse lookup via `WorkspaceTokenService`, (3) default/primary workspace from configuration. All workspaces are served on a single port; no per-workspace Kestrel hosts are spawned. - -**Covered by:** `WorkspaceResolutionMiddleware`, `WorkspaceContext`, `WorkspaceTokenService`, `WorkspaceAuthMiddleware` - -## FR-MCP-044 Shared Database Multi-Tenancy - -All workspace data shall be stored in a single shared SQLite database with a `WorkspaceId` discriminator column on every entity table. EF Core global query filters ensure workspace data isolation per-request. Cross-workspace queries use `IgnoreQueryFilters()` for admin operations. - -**Covered by:** `McpDbContext`, `WorkspaceContext`, all entity types (`WorkspaceId` property) - -## FR-MCP-045 Cross-Workspace TODO Move - -The server shall support moving a TODO item from one workspace to another via REST (`POST /mcpserver/todo/{id}/move`) and STDIO (`todo_move` MCP tool), preserving all item fields including implementation tasks, requirements, and metadata. The move is implemented as create-in-target then delete-from-source. - -**Covered by:** `TodoController.MoveAsync`, `FwhMcpTools.TodoMove`, `TodoMoveRequest`, `TodoServiceResolver` - -## FR-MCP-046 Voice Conversation Sessions - -The server shall provide voice-enabled agent interaction via Copilot CLI, supporting session creation with device binding, voice turn processing (synchronous and SSE streaming), transcript retrieval, session interruption, ESC-key injection for generation cancellation, and automatic idle session cleanup with configurable timeout. Voice connections can attach to running pooled agents, including agents currently processing one-shot work. One active session per device is enforced. - -**Covered by:** `VoiceController`, `VoiceConversationService`, `VoiceConversationOptions`, `CopilotInteractiveSession` - -## FR-MCP-047 Desktop Process Launch - -The server shall support launching interactive desktop processes from a Windows service (LocalSystem) context using `CreateProcessAsUser` with WTS session token negotiation, enabling Copilot CLI and other GUI/console tools to run on the interactive desktop with stdio pipe redirection or visible console windows. - -**Covered by:** `DesktopProcessLauncher`, `NativeMethods` - -## FR-MCP-048 YAML Configuration Support - -The server shall support `appsettings.yaml` as an optional configuration source loaded after `appsettings.json` with hot reload, enabling YAML-format configuration alongside JSON for local-only overrides. - -**Covered by:** `Program.cs` (`AddYamlFile`), `NetEscapades.Configuration.Yaml` - -## FR-MCP-049 Prompt Template Registry - -The server shall provide a global prompt template registry with REST API endpoints (`/mcpserver/templates`) and MCP tools for CRUD operations (list, get, create, update, delete) and test/render operations. Templates are stored as YAML files, support Handlebars rendering with declared variables, and are filterable by category, tag, and keyword. A Director TUI tab shall enable template browsing and preview. - -**Covered by:** `PromptTemplateController`, `PromptTemplateService`, `PromptTemplateRenderer`, `FwhMcpTools` (6 template tools), `TemplateClient`, `TemplatesScreen` - -## FR-MCP-050 Template Externalization - -The server shall load system prompt templates (marker prompt, TODO prompts, pairing HTML pages) from external YAML files via provider interfaces. The marker prompt template is required to exist in the external file; the server shall fail critically if it is missing. Configuration overrides (`Mcp:MarkerPromptTemplate`, `Mcp:TodoPrompts`) take precedence over file-loaded templates. This enables runtime template customization without recompilation. - -**Covered by:** `IMarkerPromptProvider`, `FileMarkerPromptProvider`, `ITodoPromptProvider`, `TodoPromptProvider`, `PairingHtmlRenderer` - -## FR-MCP-051 System-Wide Default Copilot Model - -The server SHALL allow configuration of a system-wide default Copilot model (e.g., `gpt-5.3-codex`) that is applied consistently across all Copilot session types — server-initiated CLI invocations (`CopilotClientOptions.Model`), voice conversation sessions (`VoiceConversationOptions.CopilotModel`), and built-in agent type defaults (`AgentDefaults`). The configured model SHALL be overridable per-workspace via agent configuration and per-invocation via explicit parameters. - -**Technical Implementation:** [TR-MCP-CFG-005](./Technical-Requirements.md#tr-mcp-cfg-005) | [Details](./TR-per-FR-Mapping.md#fr-mcp-051) - -## FR-MCP-052 Agent Pool Runtime Orchestration - -The server shall maintain a configured pool of long-lived agent processes and route agent execution through pooled agents instead of independent ad-hoc launches. - -Agent pool definitions shall include: `AgentName`, `AgentPath`, `AgentModel`, `AgentSeed`, and `AgentParameters`. - -**Covered by:** `AgentPoolOptions` *(planned)*, `AgentPoolService` *(planned)* - -## FR-MCP-053 One-Shot Queueing and Deferred Attachment - -One-shot requests shall execute through the agent pool queue. If no eligible pooled agent is available, requests shall be queued and dequeued when an agent becomes available. - -One-shot requesters shall receive processing lifecycle notifications and may attach to the running agent via interactive voice session or read-only response stream. - -**Covered by:** `AgentPoolQueueService` *(planned)*, `AgentPoolController` *(planned)* - -## FR-MCP-054 Agent Pool Availability and Control Endpoints - -The server shall expose endpoints to list pooled agents and real-time availability, and provide runtime controls for connect, start, stop, recycle, queue inspection, queue cancel/remove, queue reorder (queued items only), and free-form one-shot enqueue. - -The server shall expose a dedicated Agent Pool notification SSE stream with payload fields `AgentName`, `LastRequestPrompt`, and `SessionId`. - -**Covered by:** `AgentPoolController` *(planned)*, `AgentPoolNotificationService` *(planned)* - -## FR-MCP-055 Default Agent Selection by Request Intent - -If a request omits `AgentName`, the server shall determine the request intent and select the configured default agent for that intent using intent-default flags. - -One-shot endpoint context values shall support: `Plan`, `Status`, `Implement`, and `AdHoc`. - -**Covered by:** `AgentPoolIntentResolver` *(planned)*, `AgentPoolService` *(planned)* - -## FR-MCP-056 Template-Aware One-Shot Prompt Resolution - -One-shot requests shall support template-driven and ad-hoc prompt modes. Template mode accepts `promptTemplateId` with optional values dictionary and workspace-context-derived values; caller-provided values override workspace context on key conflicts. - -The server shall expose an endpoint that accepts prompt template ID plus values dictionary and returns the rendered prompt. - -If context is provided without template ID, the server shall use current context-based template resolution. For `AdHoc` context without template ID, explicit ad-hoc prompt text is required. - -One-shot endpoint template rendering shall support an `id` parameter used to populate `{id}` placeholders in templates. `id` is required only for template-resolved requests. - -**Covered by:** `PromptTemplateController` *(planned extension)*, `AgentPoolController` *(planned)* - -## FR-MCP-057 Director Agent Pool Management UI - -*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-057-director-agent-pool-management-ui)* - -## FR-MCP-058 Interactive Presence Signaling - -When a user disconnects from an interactive response stream, the server shall send `User is AFK.` to the agent session. - -When a user reestablishes an interactive response stream connection, the server shall send `User is here.` to the agent after stream establishment. - -These presence messages do not apply to one-shot sessions. - -**Covered by:** `AgentPoolStreamService` *(planned)*, `VoiceConversationService` *(planned extension)* - -## FR-MCP-059 DI-Centered Single Source of Truth State Flow - -The system SHALL enforce a DI-centered Single Source of Truth architecture across `McpServer.Support.Mcp`: authoritative mutable data sources must be owned by DI-registered singleton or scoped services, services shall notify state availability/changes via `INotifyPropertyChanged`, and consumers shall pull current state from the owning service rather than receiving pushed data payloads. - -**Technical Implementation:** [TR-MCP-ARCH-002](./Technical-Requirements.md#tr-mcp-arch-002) | [Details](./TR-per-FR-Mapping.md#fr-mcp-059) - -## FR-MCP-060 Director MVVM/CQRS Full Endpoint Coverage - -*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-060-director-mvvmcqrs-full-endpoint-coverage)* - -## FR-MCP-061 Canonical TODO and Session Identifier Conventions - -The server shall enforce canonical identifier conventions for newly created TODO and session log payloads: - -- TODO IDs must match `--###` using uppercase kebab-case. -- Session IDs must match `--` and be prefixed by the exact `sourceType`/`agent`. -- Request IDs must match `req--`. - -Validation failures return client-visible errors without mutating persisted data. - -**Covered by:** `TodoValidator`, `TodoService`, `SqliteTodoService`, `SessionLogIdentifierValidator`, `SessionLogController`, `SessionLogService` - -## FR-MCP-062 Workspace Change Notifications - -The server shall provide a real-time workspace change notification system that publishes create/update/delete domain events for workspace mutations (TODOs, session logs, repo files, context sync, tool registry, tool buckets, workspaces, GitHub operations, marker lifecycle, agents, and requirements) over Server-Sent Events at `GET /mcpserver/events`, with optional category filtering. - -**Covered by:** `IChangeEventBus`, `ChannelChangeEventBus`, `EventStreamController`, `TodoService`, `SqliteTodoService`, `SessionLogService`, `RepoFileService`, `ToolRegistryService`, `ToolBucketService`, `WorkspaceService`, `WorkspaceController`, `AgentService`, `RequirementsDocumentService`, `IngestionCoordinator`, `GitHubController`, `WorkspaceProcessManager` - -## FR-MCP-063 Workspace GitHub OAuth Bootstrap, Token Lifecycle, and Actions Control - -The server shall provide workspace-scoped GitHub authentication controls and workflow operations that support OAuth bootstrap and secure token usage without breaking existing gh CLI compatibility. - -Functional behavior shall include: - -- OAuth bootstrap discovery endpoints exposing configured client ID, redirect URI, authorize endpoint, and scopes. -- Workspace-scoped token lifecycle endpoints to set, inspect, and revoke GitHub tokens. -- Authenticated GitHub execution path that prefers stored workspace token credentials and falls back to ambient gh auth only when policy allows it. -- GitHub Actions workflow run management endpoints for list/detail/rerun/cancel operations. -- Typed client parity for all new GitHub auth and workflow run endpoints. - -**Technical Implementation:** [TR-MCP-GH-001](./Technical-Requirements.md#tr-mcp-gh-001) | [TR-MCP-GH-002](./Technical-Requirements.md#tr-mcp-gh-002) | [TR-MCP-GH-003](./Technical-Requirements.md#tr-mcp-gh-003) | [TR-MCP-GH-004](./Technical-Requirements.md#tr-mcp-gh-004) - -**Covered by:** `GitHubIntegrationOptions`, `FileGitHubWorkspaceTokenStore`, `GitHubController`, `GitHubCliService`, `ProcessRunner`, `GitHubClient` - -#### FR-MCP-064: Marketing and Adoption Documentation -The system SHALL provide marketing-oriented documentation that clearly explains what McpServer is, its key feature set, why adopters need it, and the currently supported UI tooling surfaces (including VS extension and Web UI experiences). -**Technical Implementation:** [TR-MCP-DOC-001](./Technical-Requirements.md#tr-mcp-doc-001) | [Details](./TR-per-FR-Mapping.md#fr-mcp-064) +# Functional Requirements (MCP Server) + +## FR-SUPPORT-010 MCP Context Unification + +Local MCP server providing context retrieval, TODO management, repository access, session logging, and ingestion capabilities for AI agent integration. + +**Covered by:** `ContextController`, `TodoController`, `RepoController`, `SessionLogController`, `McpServerMcpTools`, `McpDbContext`, `HybridSearchService`, `EmbeddingService`, `VectorIndexService`, `Fts5SearchService`, `RepoFileService`, `IngestionCoordinator` + +## FR-MCP-001 Configurable workspace root and paths + +The server shall support configurable `RepoRoot`, `TodoFilePath`, `DataDirectory`, and index paths. + +**Covered by:** `IngestionOptions`, `IOptions` + +## FR-MCP-002 TODO management API + +The server shall provide CRUD/query operations for TODO items over REST and STDIO. + +**Covered by:** `TodoController`, `TodoService`, `SqliteTodoService` + +## FR-MCP-003 Session log ingestion and query + +The server shall ingest session logs and support searchable queries. + +**Covered by:** `SessionLogController`, `SessionLogService` + +## FR-MCP-004 Hybrid context search + +The server shall support FTS and vector search over indexed content. + +**Covered by:** `HybridSearchService`, `Fts5SearchService`, `VectorIndexService`, `EmbeddingService` + +## FR-MCP-005 GitHub issue sync + +The server shall support GitHub issue lifecycle integration and ISSUE-* TODO synchronization. + +**Covered by:** `GitHubController`, `GitHubCliService`, `IssueTodoSyncService` + +## FR-MCP-006 Multi-source ingestion + +The server shall ingest repository files, session logs, external docs, and issue content. + +**Covered by:** `IngestionCoordinator`, `RepoIngestor`, `SessionLogIngestor`, `ExternalDocsIngestor`, `GitHubIngestor`, `IssueIngestor` + +## FR-MCP-007 Dual transport + +The server shall support HTTP and STDIO MCP transports. + +**Covered by:** `Program.cs`, `McpServerMcpTools`, `McpStdioHost` + +## FR-MCP-008 Containerized deployment + +The server shall support containerized deployment and packaged distribution. + +**Covered by:** `Dockerfile`, `docker-compose.mcp.yml` + +## FR-MCP-009 Workspace Management + +The server shall support dynamic workspace registration, configuration, and lifecycle management — replacing static instance configuration — with directory scaffolding and Base64URL-encoded path keys. All workspaces are served on a single port via `X-Workspace-Path` header resolution (see FR-MCP-043). + +**Covered by:** `WorkspaceController`, `WorkspaceService`, `WorkspaceConfigEntry` + +## FR-MCP-011 Workspace Process Orchestration + +The server shall manage workspace lifecycle via marker files: write `AGENTS-README-FIRST.yaml` on start, remove on stop. All workspaces share the single host process and port. Automatic startup of all registered workspaces writes markers on service start. + +**Covered by:** `WorkspaceProcessManager`, `IWorkspaceProcessManager`, `MarkerFileService` + +## FR-MCP-012 Tool Registry + +Agents shall be able to discover tools by keyword search across global and workspace-scoped tool definitions, and install tool definitions from GitHub-backed bucket repositories. + +**Covered by:** `ToolRegistryController`, `ToolRegistryService`, `ToolBucketService` + +## FR-MCP-013 Per-Workspace Auth Tokens + +The server shall protect all `/mcpserver/*` API endpoints with per-workspace cryptographic tokens that rotate on each service restart. Tokens are discoverable via the `AGENTS-README-FIRST.yaml` marker file, checked via the `X-Api-Key` header or `api_key` query parameter, and enforced by `WorkspaceAuthMiddleware`. Workspace resolution uses a three-tier chain: `X-Workspace-Path` header → API key reverse lookup → default workspace (see FR-MCP-043). + +**Covered by:** `WorkspaceAuthMiddleware`, `WorkspaceTokenService`, `WorkspaceResolutionMiddleware`, `MarkerFileService` + +## FR-MCP-014 Pairing Web UI + +*Moved to [Requirements-WebUI.md](Requirements-WebUI.md#fr-mcp-014-pairing-web-ui)* + +## FR-MCP-015 Tunnel Providers + +The server shall expose its HTTP interface to the internet via pluggable tunnel providers (ngrok, Cloudflare, FRP) configured through a strategy pattern and registered as hosted services. + +**Covered by:** `NgrokTunnelProvider`, `CloudflareTunnelProvider`, `FrpTunnelProvider` + +## FR-MCP-016 MCP Streamable HTTP Transport + +The server shall expose a native MCP protocol endpoint at `/mcp-transport` coexisting with the REST API on the same port, enabling standard MCP client connections via `ModelContextProtocol.AspNetCore`. + +**Covered by:** `Program.cs` (MapMcp), `ModelContextProtocol.AspNetCore` + +## FR-MCP-017 Windows Service + +The server shall run as a Windows service with automatic startup, failure recovery (restart on failure with 60 s delay), and PowerShell-based install/update/uninstall management. + +**Covered by:** `Program.cs` (UseWindowsService), `Manage-McpService.ps1` + +## FR-MCP-018 Marker File Agent Discovery + +When a workspace is started, the server shall write an `AGENTS-README-FIRST.yaml` marker file to the workspace root containing the shared host port, all endpoint paths, a machine-readable prompt, and PID. All markers point to the same port; workspace identity is resolved via the `X-Workspace-Path` header. The marker shall be removed when the workspace is stopped. + +**Covered by:** `MarkerFileService`, `WorkspaceProcessManager` + +## FR-MCP-019 Workspace Host Controller Isolation + +*Obsolete — replaced by single-app multi-tenant model (FR-MCP-043).* All controllers are available on the single host. Workspace lifecycle management endpoints on `WorkspaceController` remain admin-only. + +## FR-MCP-020 Workspace Auto-Start on Service Startup + +On service startup, the server shall automatically write marker files for all workspaces already registered, restoring agent discoverability without manual intervention. All workspaces share the single host port. + +**Covered by:** `WorkspaceProcessManager` (IHostedService.StartAsync) + +## FR-MCP-021 Workspace Auto-Init and Auto-Start on Creation + +When a new workspace is registered, the server shall automatically initialize the workspace directory scaffold (todo.yaml, mcp.db, docs structure) and write its marker file, so the workspace is immediately operational on the shared port. + +**Covered by:** `WorkspaceController` POST, `WorkspaceService.InitAsync` + +## FR-MCP-022 Tool Registry Default Bucket Seeding + +On first startup, the server shall seed default tool buckets from configuration (`Mcp:ToolRegistry:DefaultBuckets`) if they are not already registered, ensuring new installations have the primary tool repository available without manual setup. + +**Covered by:** `ToolRegistryOptions`, `Program.cs` + +## FR-MCP-023 AI-Assisted Requirements Analysis + +The server shall provide a requirements analysis capability that invokes the Copilot CLI to examine a TODO item's title, description, and technical details, identify matching existing FR/TR IDs from the project docs, create new FR/TR entries for unaddressed functionality, and persist the assigned IDs back to the TODO item. + +**Covered by:** `RequirementsService`, `IRequirementsService`, `ICopilotClient` + +## FR-MCP-024 Markdown Session Log Ingestion + +The ingestion pipeline shall parse legacy Markdown session log files (matching a `# Session Log – {title}` header pattern) into the unified session log schema alongside JSON session logs, enabling retroactive indexing of pre-existing agent session records. + +**Covered by:** `MarkdownSessionLogParser`, `SessionLogIngestor` + +## FR-MCP-025 Primary Workspace Detection and Deduplication + +One workspace is designated as the **primary** workspace — served by the host process directly with no child `WebApplication` spun up. Only a marker file is written. Resolution order: (1) first enabled workspace with `IsPrimary = true` and lowest port; (2) enabled workspace with lowest port if none marked primary; (3) no primary if no workspaces enabled. + +## FR-LOC-001 Localization Support + +Localization and internationalization support for the MCP server. *(Planned — implementation scope TBD.)* + +## FR-MCP-026 OIDC Authentication + +The server shall support standards-based OIDC JWT Bearer authentication for management endpoints using a configurable open-source .NET OIDC provider. Optional external identity federation (for example, GitHub) may be configured through that provider. Management endpoints (agent mutations) require JWT; read endpoints use existing API key auth. + +**Covered by:** `OidcAuthOptions`, `Program.cs`, `AgentController`, `Setup-McpKeycloak.ps1`, `setup-mcp-keycloak.sh` + +## FR-MCP-027 Agent Definition Management + +The server shall provide CRUD operations for agent type definitions with built-in defaults for well-known AI coding agents (copilot, cline, cursor, windsurf, claude-code, aider, continue). Built-in definitions are seeded on first run and cannot be deleted. + +**Covered by:** `AgentController`, `AgentService`, `AgentDefaults`, `AgentDefinitionEntity` + +## FR-MCP-028 Per-Workspace Agent Configuration + +The server shall support per-workspace agent configuration with overrides for launch command, models, branch strategy, seed prompt, instruction files, isolation strategy, restart policy, and marker additions. Agents can be banned per-workspace or globally with optional PR-gated unbanning. All agent lifecycle events (add, launch, exit, ban, unban, delete, merge, init) are logged for audit. + +**Covered by:** `AgentController`, `AgentService`, `AgentWorkspaceEntity`, `AgentEventLogEntity`, `AgentHealthMonitorService` + +## FR-MCP-029 CQRS Framework + +A standalone CQRS framework (`McpServer.Cqrs`) shall provide async command/query dispatch with a Result monad, decimal correlation IDs (`baseId.counter`), pipeline behaviors, and an `ILoggerProvider` implementation that auto-enriches structured logs with decomposed correlation context. The Dispatcher shall automatically log Result outcomes (success at Debug, errors at Error/Warning). + +**Status:** ✅ Complete + +**Covered by:** `McpServer.Cqrs` project (`Dispatcher`, `CallContext`, `CorrelationId`, `Result`, `IPipelineBehavior`), `McpServer.Cqrs.Mvvm` (IViewModelRegistry, ViewModelRegistryExtensions), `McpServer.UI.Core` (WorkspaceListViewModel, WorkspacePolicyViewModel, AddUiCore DI extension) + +**Implementation:** 37 unit tests passing. Provides `ICommand`/`IQuery` message types, `ICommandHandler<,>`/`IQueryHandler<,>` handlers, `Dispatcher` with pipeline behavior chain, `CallContext` with `CorrelationId` for structured logging, and `Result` monad with success/error paths. MVVM layer adds `IViewModelRegistry` for CLI exec command support. + +## FR-MCP-030 Director CLI + +*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-030-director-cli)* + +## FR-MCP-031 McpServer Management Web UI + +*Moved to [Requirements-WebUI.md](Requirements-WebUI.md#fr-mcp-031-mcpserver-management-web-ui)* + +## FR-MCP-032 Enhanced GitHub Integration + +Enhanced GitHub integration capabilities including GitHub federation through the configured OIDC provider for user authentication, and GitHub OAuth for agent workspace management and PR workflows. *(Planned — tracked as high-priority TODO.)* + +## FR-MCP-033 Natural Language Policy Management + +A Copilot-integrated prompt tool that accepts natural language policy directives (e.g. "Ban chinese sources from all workspaces") and translates them into workspace configuration changes across all or targeted workspaces. Each policy change is session-logged per affected workspace with action type `policy_change`. + +**Covered by:** `WorkspaceController` (`POST /mcpserver/workspace/policy`), `WorkspacePolicyService`, `WorkspacePolicyDirectiveParser`, `McpServerMcpTools.workspace_policy_apply` + +## FR-MCP-034 Workspace Compliance Configuration + +Per-workspace compliance configuration supporting four ban lists: `BannedLicenses` (SPDX identifiers), `BannedCountriesOfOrigin` (ISO 3166-1 alpha-2 codes), `BannedOrganizations`, and `BannedIndividuals`. Ban lists are conditionally rendered into the AGENTS-README-FIRST.yaml marker prompt via Handlebars templates. Agents must verify compliance before adding dependencies and log violations. + +**Covered by:** `WorkspaceDto`, `WorkspaceCreateRequest`, `WorkspaceUpdateRequest`, `MarkerFileService` + +## FR-MCP-035 Agent Values and Conduct Enforcement + +The marker prompt shall include mandatory sections for: absolute honesty, correctness above speed, complete decision documentation, professional representation and audit trail (commits, PRs, issues logged in full), and source attribution (web references logged). These are non-configurable and always present. + +**Covered by:** `templates/prompt-templates.yaml` (default-marker-prompt) + +## FR-MCP-036 Audited Copilot Interactions + +Every server-initiated Copilot interaction must be session-logged in every affected workspace. An `AuditedCopilotClient` decorator wraps `ICopilotClient` to create session log entries before and after each call, with action type `copilot_invocation`. + +**Covered by:** `AuditedCopilotClient`, `Program.cs` DI registration, `McpStdioHost` DI registration, `CopilotServiceCollectionExtensions` + +## FR-MCP-037 Director CLI Exec Command + +*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-037-director-cli-exec-command)* + +## FR-MCP-038 Session Continuity Protocol + +Agents must follow a session continuity protocol: at session start, read the marker file, query recent session logs (limit=5), query current TODOs, and read Requirements-Matrix.md. During long sessions, post updated session logs every ~10 interactions. Requirements and design decisions must be captured as they emerge, not deferred. + +**Covered by:** `templates/prompt-templates.yaml` (default-marker-prompt) + +## FR-MCP-039 MCP Context Indexing for New Projects + +All source files from `McpServer.Cqrs`, `McpServer.Cqrs.Mvvm`, `McpServer.UI.Core`, and `McpServer.Director` shall be indexed into the MCP context store for semantic search. The marker prompt lists these projects in the Available Capabilities section. + +**Covered by:** `Program.cs` / `McpStdioHost` `PostConfigure` allowlist merge, `appsettings.yaml` `Mcp:RepoAllowlist`, `templates/prompt-templates.yaml` (default-marker-prompt) + +## FR-MCP-040 Requirements Document CRUD Management + +The server shall support CRUD operations for Functional Requirements (FR), Technical Requirements (TR), Testing Requirements (TEST), and FR-to-TR mapping rows backed by the canonical project requirements Markdown files. + +**Covered by:** `RequirementsController`, `RequirementsDocumentService`, `IRequirementsRepository` + +## FR-MCP-041 Requirements Document Generation + +The server shall expose a requirements document generation endpoint that renders any canonical requirements document as Markdown and can return all documents together as a ZIP archive with canonical filenames. + +**Covered by:** `RequirementsController` (`/mcpserver/requirements/generate`), `RequirementsDocumentService`, `RequirementsDocumentRenderer` + +## FR-MCP-042 Requirements Management MCP Tools + +The STDIO MCP tool surface shall expose requirements management tools for listing, generating, creating, updating, and deleting requirements entries so AI agents can manage requirements directly from a conversation. + +**Covered by:** `FwhMcpTools` (`requirements_list`, `requirements_generate`, `requirements_create`, `requirements_update`, `requirements_delete`), `RequirementsDocumentService` + +## FR-MCP-043 Multi-Tenant Workspace Resolution + +The server shall resolve the target workspace per-request using a three-tier resolution chain: (1) `X-Workspace-Path` header (highest priority), (2) API key reverse lookup via `WorkspaceTokenService`, (3) default/primary workspace from configuration. All workspaces are served on a single port; no per-workspace Kestrel hosts are spawned. + +**Covered by:** `WorkspaceResolutionMiddleware`, `WorkspaceContext`, `WorkspaceTokenService`, `WorkspaceAuthMiddleware` + +## FR-MCP-044 Shared Database Multi-Tenancy + +All workspace data shall be stored in a single shared SQLite database with a `WorkspaceId` discriminator column on every entity table. EF Core global query filters ensure workspace data isolation per-request. Cross-workspace queries use `IgnoreQueryFilters()` for admin operations. + +**Covered by:** `McpDbContext`, `WorkspaceContext`, all entity types (`WorkspaceId` property) + +## FR-MCP-045 Cross-Workspace TODO Move + +The server shall support moving a TODO item from one workspace to another via REST (`POST /mcpserver/todo/{id}/move`) and STDIO (`todo_move` MCP tool), preserving all item fields including implementation tasks, requirements, and metadata. The move is implemented as create-in-target then delete-from-source. + +**Covered by:** `TodoController.MoveAsync`, `FwhMcpTools.TodoMove`, `TodoMoveRequest`, `TodoServiceResolver` + +## FR-MCP-046 Voice Conversation Sessions + +The server shall provide voice-enabled agent interaction via Copilot CLI, supporting session creation with device binding, voice turn processing (synchronous and SSE streaming), transcript retrieval, session interruption, ESC-key injection for generation cancellation, and automatic idle session cleanup with configurable timeout. Voice connections can attach to running pooled agents, including agents currently processing one-shot work. One active session per device is enforced. + +**Covered by:** `VoiceController`, `VoiceConversationService`, `VoiceConversationOptions`, `CopilotInteractiveSession` + +## FR-MCP-047 Desktop Process Launch + +The server shall support launching interactive desktop processes from a Windows service (LocalSystem) context using `CreateProcessAsUser` with WTS session token negotiation, enabling Copilot CLI and other GUI/console tools to run on the interactive desktop with stdio pipe redirection or visible console windows. + +**Covered by:** `DesktopProcessLauncher`, `NativeMethods` + +## FR-MCP-048 YAML Configuration Support + +The server shall support `appsettings.yaml` as an optional configuration source loaded after `appsettings.json` with hot reload, enabling YAML-format configuration alongside JSON for local-only overrides. + +**Covered by:** `Program.cs` (`AddYamlFile`), `NetEscapades.Configuration.Yaml` + +## FR-MCP-049 Prompt Template Registry + +The server shall provide a global prompt template registry with REST API endpoints (`/mcpserver/templates`) and MCP tools for CRUD operations (list, get, create, update, delete) and test/render operations. Templates are stored as YAML files, support Handlebars rendering with declared variables, and are filterable by category, tag, and keyword. A Director TUI tab shall enable template browsing and preview. + +**Covered by:** `PromptTemplateController`, `PromptTemplateService`, `PromptTemplateRenderer`, `FwhMcpTools` (6 template tools), `TemplateClient`, `TemplatesScreen` + +## FR-MCP-050 Per-Agent Workspace Runtime Management + +The server shall provide runtime management for workspace-bound agents, including process launch/stop/status, configurable isolation modes (`none`, `worktree`, `clone`), branch strategy handling (`direct`, `feature-branch`, `worktree`), session-log linkage to known agent definitions, marker-file agent-specific instruction sections, and restart-policy-driven health monitoring. + +**Covered by:** `AgentService`, `AgentController`, `IAgentProcessManager`, `AgentProcessManager`, `IAgentIsolationStrategy`, `AgentIsolationStrategyResolver`, `IAgentBranchStrategy`, `AgentBranchStrategyResolver`, `WorkspaceProcessManager`, `SessionLogService`, `AgentHealthMonitorService` + +## FR-MCP-051 System-Wide Default Copilot Model + +The server SHALL allow configuration of a system-wide default Copilot model (e.g., `gpt-5.3-codex`) that is applied consistently across all Copilot session types — server-initiated CLI invocations (`CopilotClientOptions.Model`), voice conversation sessions (`VoiceConversationOptions.CopilotModel`), and built-in agent type defaults (`AgentDefaults`). The configured model SHALL be overridable per-workspace via agent configuration and per-invocation via explicit parameters. + +**Technical Implementation:** [TR-MCP-CFG-005](./Technical-Requirements.md#tr-mcp-cfg-005) | [Details](./TR-per-FR-Mapping.md#fr-mcp-051) + +## FR-MCP-052 Agent Pool Runtime Orchestration + +The server shall maintain a configured pool of long-lived agent processes and route agent execution through pooled agents instead of independent ad-hoc launches. + +Agent pool definitions shall include: `AgentName`, `AgentPath`, `AgentModel`, `AgentSeed`, and `AgentParameters`. + +**Covered by:** `AgentPoolOptions` *(planned)*, `AgentPoolService` *(planned)* + +## FR-MCP-053 One-Shot Queueing and Deferred Attachment + +One-shot requests shall execute through the agent pool queue. If no eligible pooled agent is available, requests shall be queued and dequeued when an agent becomes available. + +One-shot requesters shall receive processing lifecycle notifications and may attach to the running agent via interactive voice session or read-only response stream. + +**Covered by:** `AgentPoolQueueService` *(planned)*, `AgentPoolController` *(planned)* + +## FR-MCP-054 Agent Pool Availability and Control Endpoints + +The server shall expose endpoints to list pooled agents and real-time availability, and provide runtime controls for connect, start, stop, recycle, queue inspection, queue cancel/remove, queue reorder (queued items only), and free-form one-shot enqueue. + +The server shall expose a dedicated Agent Pool notification SSE stream with payload fields `AgentName`, `LastRequestPrompt`, and `SessionId`. + +**Covered by:** `AgentPoolController` *(planned)*, `AgentPoolNotificationService` *(planned)* + +## FR-MCP-055 Default Agent Selection by Request Intent + +If a request omits `AgentName`, the server shall determine the request intent and select the configured default agent for that intent using intent-default flags. + +One-shot endpoint context values shall support: `Plan`, `Status`, `Implement`, and `AdHoc`. + +**Covered by:** `AgentPoolIntentResolver` *(planned)*, `AgentPoolService` *(planned)* + +## FR-MCP-056 Template-Aware One-Shot Prompt Resolution + +One-shot requests shall support template-driven and ad-hoc prompt modes. Template mode accepts `promptTemplateId` with optional values dictionary and workspace-context-derived values; caller-provided values override workspace context on key conflicts. + +The server shall expose an endpoint that accepts prompt template ID plus values dictionary and returns the rendered prompt. + +If context is provided without template ID, the server shall use current context-based template resolution. For `AdHoc` context without template ID, explicit ad-hoc prompt text is required. + +One-shot endpoint template rendering shall support an `id` parameter used to populate `{id}` placeholders in templates. `id` is required only for template-resolved requests. + +**Covered by:** `PromptTemplateController` *(planned extension)*, `AgentPoolController` *(planned)* + +## FR-MCP-057 Director Agent Pool Management UI + +*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-057-director-agent-pool-management-ui)* + +## FR-MCP-058 Interactive Presence Signaling + +When a user disconnects from an interactive response stream, the server shall send `User is AFK.` to the agent session. + +When a user reestablishes an interactive response stream connection, the server shall send `User is here.` to the agent after stream establishment. + +These presence messages do not apply to one-shot sessions. + +**Covered by:** `AgentPoolStreamService` *(planned)*, `VoiceConversationService` *(planned extension)* + +## FR-MCP-059 DI-Centered Single Source of Truth State Flow + +The system SHALL enforce a DI-centered Single Source of Truth architecture across `McpServer.Support.Mcp`: authoritative mutable data sources must be owned by DI-registered singleton or scoped services, services shall notify state availability/changes via `INotifyPropertyChanged`, and consumers shall pull current state from the owning service rather than receiving pushed data payloads. + +**Technical Implementation:** [TR-MCP-ARCH-002](./Technical-Requirements.md#tr-mcp-arch-002) | [Details](./TR-per-FR-Mapping.md#fr-mcp-059) + +## FR-MCP-060 Director MVVM/CQRS Full Endpoint Coverage + +*Moved to [Requirements-Director.md](Requirements-Director.md#fr-mcp-060-director-mvvmcqrs-full-endpoint-coverage)* + +## FR-MCP-061 Canonical TODO and Session Identifier Conventions + +The server shall enforce canonical identifier conventions for newly created TODO and session log payloads: + +- Persisted TODO IDs must match either `--###` using uppercase kebab-case or `ISSUE-{number}` for canonical GitHub-backed TODOs. +- Create requests may use `ISSUE-NEW` only as a temporary server-side alias for immediate GitHub-backed TODO creation; persisted TODO IDs must still be canonical. +- Session IDs must match `--` and be prefixed by the exact `sourceType`/`agent`. +- Request IDs must match `req--`. + +Validation failures return client-visible errors without mutating persisted data. + +**Covered by:** `TodoValidator`, `TodoService`, `SqliteTodoService`, `TodoCreationService`, `SessionLogIdentifierValidator`, `SessionLogController`, `SessionLogService` + +## FR-MCP-062 Workspace Change Notifications + +The server shall provide a real-time workspace change notification system that publishes create/update/delete domain events for workspace mutations (TODOs, session logs, repo files, context sync, tool registry, tool buckets, workspaces, GitHub operations, marker lifecycle, agents, and requirements) over Server-Sent Events at `GET /mcpserver/events`, with optional category filtering. + +**Covered by:** `IChangeEventBus`, `ChannelChangeEventBus`, `EventStreamController`, `TodoService`, `SqliteTodoService`, `SessionLogService`, `RepoFileService`, `ToolRegistryService`, `ToolBucketService`, `WorkspaceService`, `WorkspaceController`, `AgentService`, `RequirementsDocumentService`, `IngestionCoordinator`, `GitHubController`, `WorkspaceProcessManager` + +## FR-MCP-063 Workspace GitHub OAuth Bootstrap, Token Lifecycle, and Actions Control + +The server shall provide workspace-scoped GitHub authentication controls and workflow operations that support OAuth bootstrap and secure token usage without breaking existing gh CLI compatibility. + +Functional behavior shall include: + +- OAuth bootstrap discovery endpoints exposing configured client ID, redirect URI, authorize endpoint, and scopes. +- Workspace-scoped token lifecycle endpoints to set, inspect, and revoke GitHub tokens. +- Authenticated GitHub execution path that prefers stored workspace token credentials and falls back to ambient gh auth only when policy allows it. +- GitHub Actions workflow run management endpoints for list/detail/rerun/cancel operations. +- Typed client parity for all new GitHub auth and workflow run endpoints. + +**Technical Implementation:** [TR-MCP-GH-001](./Technical-Requirements.md#tr-mcp-gh-001) | [TR-MCP-GH-002](./Technical-Requirements.md#tr-mcp-gh-002) | [TR-MCP-GH-003](./Technical-Requirements.md#tr-mcp-gh-003) | [TR-MCP-GH-004](./Technical-Requirements.md#tr-mcp-gh-004) + +**Covered by:** `GitHubIntegrationOptions`, `FileGitHubWorkspaceTokenStore`, `GitHubController`, `GitHubCliService`, `ProcessRunner`, `GitHubClient` + +#### FR-MCP-064: Marketing and Adoption Documentation +The system SHALL provide marketing-oriented documentation that clearly explains what McpServer is, its key feature set, why adopters need it, and the currently supported UI tooling surfaces (including VS extension and Web UI experiences). +**Technical Implementation:** [TR-MCP-DOC-001](./Technical-Requirements.md#tr-mcp-doc-001) | [Details](./TR-per-FR-Mapping.md#fr-mcp-064) + +## FR-MCP-065 Direct Website URL Ingestion + +The server shall ingest remote website content directly from one URL (with optional bounded same-host crawling) into the context store and GraphRAG pipeline without pre-downloading files into `docs/external`. + +**Covered by:** `ContextController` (`POST /mcpserver/context/ingest-website`), `WebsiteIngestor`, `IngestionCoordinator`, `FwhMcpTools` (`context_ingest_website`), `ContextClient.IngestWebsiteAsync` + +## FR-MCP-066 Hosted Microsoft Agent Framework Library + +The system SHALL provide a .NET 9 class library that packages an MCP-aware agent for hosting inside external .NET applications built on Microsoft Agent Framework. + +The hosted agent SHALL include a built-in workflow that treats MCP Server session logging, TODO management, repository file access, local desktop process launch, and stateful in-process PowerShell sessions as first-class primitives, allowing host applications to bootstrap/continue session logs, create and update turns, inspect and mutate TODO items, browse repository files, launch local programs, run PowerShell commands inside persistent local runspaces, drive those runspaces directly through the host-facing agent contract when needed, and execute plan/status/implementation task flows without reimplementing those integrations. + +**Status:** ✅ Complete + +**Technical Implementation:** [TR-MCP-AGENT-006](./Technical-Requirements.md#tr-mcp-agent-006) | [TR-MCP-AGENT-007](./Technical-Requirements.md#tr-mcp-agent-007) | [Details](./TR-per-FR-Mapping.md#fr-mcp-066) + +**Covered by:** `McpServer.McpAgent` (`ServiceCollectionExtensions`, `McpAgentOptions`, `Hosting/*`, `PowerShellSessions/*`, `SessionLog/*`, `Todo/*`), `McpServer.Client` (`McpServerClient`, `RepoClient`, `DesktopClient`), `McpServer.McpAgent.SampleHost` (`Program.cs`, `SampleHostPreviewFactory.cs`) + +## FR-MCP-067 Detailed Internal Server Error Responses + +The system SHALL return a detailed client-visible error description for every endpoint response that fails with HTTP 500. + +Detailed 500 responses SHALL describe the failed operation clearly enough for callers to diagnose the failure path and distinguish server faults from client mistakes, while remaining sanitized so secrets, tokens, and other sensitive internals are not exposed in the response body. + +**Technical Implementation:** [TR-MCP-HTTP-002](./Technical-Requirements.md#tr-mcp-http-002) | [Details](./TR-per-FR-Mapping.md#fr-mcp-067) + +## FR-MCP-068 Administrative Configuration Management API + +The server SHALL provide an admin-only configuration API that returns the current effective configuration as flattened key-value pairs and supports patching selected values back into `appsettings.yaml` without rewriting unrelated settings or serializing values that originate only from non-file configuration providers. + +The configuration-management endpoints SHALL require standard JWT Bearer authentication with the `admin` role. When OIDC is not configured, the endpoints SHALL remain unavailable. + +**Technical Implementation:** [TR-MCP-CFG-006](./Technical-Requirements.md#tr-mcp-cfg-006) | [Details](./TR-per-FR-Mapping.md#fr-mcp-068) + +**Covered by:** `ConfigurationController`, `AppSettingsFileService`, `Program.cs` (`ConfigurationAdmin` policy), `WorkspaceController` (shared appsettings helper reuse) + +## FR-MCP-069 Immediate GitHub-Backed TODO Creation + +The server shall support a create-time TODO identifier of `ISSUE-NEW` that immediately creates a GitHub issue, determines the resulting issue number, and persists the local TODO using the canonical `ISSUE-{number}` identifier returned by GitHub. + +This behavior shall be available through all server-side TODO creation entry points that already support normal TODO creation. Callers shall receive the canonical persisted identifier rather than the temporary `ISSUE-NEW` alias. + +**Technical Implementation:** [TR-MCP-TODO-003](./Technical-Requirements.md#tr-mcp-todo-003) | [TR-MCP-GH-005](./Technical-Requirements.md#tr-mcp-gh-005) | [Details](./TR-per-FR-Mapping.md#fr-mcp-069) + +**Covered by:** `TodoCreationService`, `GitHubCliService`, `TodoController`, `FwhMcpTools`, `VoiceConversationService` + +## FR-MCP-070 Authoritative ISSUE-* Update Sync and Immutable Descriptions + +The server shall treat MCP TODO updates as authoritative for existing `ISSUE-{number}` TODO items. When an `ISSUE-*` TODO is updated through a server TODO update surface, the server shall push the authoritative MCP state to GitHub, append a GitHub issue comment describing the applied change set, and keep the ISSUE description/body immutable after the first sync. + +Priority synchronization shall use canonical GitHub labels in the form `priority: HIGH`, `priority: MEDIUM`, or `priority: LOW`. GitHub-to-TODO refreshes for existing `ISSUE-*` items shall preserve the local priority and description that were already established by the first sync. + +**Technical Implementation:** [TR-MCP-TODO-004](./Technical-Requirements.md#tr-mcp-todo-004) | [TR-MCP-GH-006](./Technical-Requirements.md#tr-mcp-gh-006) | [Details](./TR-per-FR-Mapping.md#fr-mcp-070) + +**Covered by:** `TodoUpdateService`, `IssueTodoSyncService`, `TodoController`, `FwhMcpTools`, `VoiceConversationService` + +## FR-MCP-071 ISSUE Comment Round-Trip and GitHub-Driven Closure Reconciliation + +The server shall round-trip `ISSUE-{number}` discussion between GitHub and MCP TODOs without mutating the established TODO description. GitHub-origin issue comments shall sync into the TODO note inside a generated GitHub-comments section, while user-authored TODO note content outside that generated section shall remain preserved across subsequent syncs. + +When an `ISSUE-*` TODO is updated locally with new note text, the server shall propagate the appended TODO-authored comment back to GitHub as an issue comment. When the GitHub issue is later closed outside MCP, a GitHub-to-TODO sync shall mark the corresponding TODO as done. + +**Technical Implementation:** [TR-MCP-GH-007](./Technical-Requirements.md#tr-mcp-gh-007) | [Details](./TR-per-FR-Mapping.md#fr-mcp-071) + +**Covered by:** `IssueTodoSyncService`, `TodoUpdateService`, `GitHubController`, `TodoController` + +## FR-MCP-072 Database-Authoritative TODO Storage with YAML Projection and Audit History + +The server shall treat SQLite as the authoritative current-state store for workspace TODO items. When a configured workspace TODO document already exists and the authoritative database is empty, initialization shall import the current YAML document once into SQLite and thereafter keep `docs/Project/TODO.yaml` synchronized as a deterministic projection of authoritative database state rather than as the live writable source of truth. + +The server shall preserve TODO document metadata such as `notes`, `completed`, and `code-review-remediation.reference`, retain append-only audit history for TODO state mutations, and expose that audit history through HTTP, typed client, and MCP tool surfaces so callers can retrieve tracked TODO states even after deletion when history exists. + +**Technical Implementation:** [TR-MCP-TODO-005](./Technical-Requirements.md#tr-mcp-todo-005) | [TR-MCP-TODO-006](./Technical-Requirements.md#tr-mcp-todo-006) | [Details](./TR-per-FR-Mapping.md#fr-mcp-072) + +**Covered by:** `SqliteTodoService`, `TodoYamlFileSerializer`, `TodoController`, `TodoClient`, `McpServerMcpTools`, `TodoServiceFactory` + diff --git a/docs/Project/Requirements-Matrix.md b/docs/Project/Requirements-Matrix.md index 031bb8d5..c1c4e8c9 100644 --- a/docs/Project/Requirements-Matrix.md +++ b/docs/Project/Requirements-Matrix.md @@ -1,145 +1,176 @@ -# Requirements Matrix (MCP Server) - -Traceability policy: see `Requirements-Traceability-Policy.md`. - -| Requirement | Status | Source Files | -| --- | --- | --- | -| FR-SUPPORT-010 | ✅ Complete | ContextController, TodoController, RepoController, SessionLogController, McpServerMcpTools, HybridSearchService, Fts5SearchService, VectorIndexService | -| FR-MCP-001 | ✅ Complete | IngestionOptions, IOptions | -| FR-MCP-002 | ✅ Complete | TodoController, TodoService, SqliteTodoService | -| FR-MCP-003 | ✅ Complete | SessionLogController, SessionLogService | -| FR-MCP-004 | ✅ Complete | HybridSearchService, Fts5SearchService, VectorIndexService | -| FR-MCP-005 | ✅ Complete | GitHubController, GitHubCliService, IssueTodoSyncService | -| FR-MCP-006 | ✅ Complete | IngestionCoordinator, RepoIngestor, SessionLogIngestor | -| FR-MCP-007 | ✅ Complete | Program.cs, McpServerMcpTools, McpStdioHost | -| FR-MCP-008 | ✅ Complete | Dockerfile, docker-compose.mcp.yml | -| FR-MCP-009 | ✅ Complete | WorkspaceController, WorkspaceService | -| FR-MCP-011 | ✅ Complete | WorkspaceProcessManager | -| FR-MCP-012 | ✅ Complete | ToolRegistryController, ToolRegistryService, ToolBucketService | -| FR-MCP-013 | ✅ Complete | WorkspaceAuthMiddleware, WorkspaceTokenService, MarkerFileService | -| FR-MCP-014 | ✅ Complete | PairingHtml, PairingOptions, Program.cs (/pair) | -| FR-MCP-015 | ✅ Complete | NgrokTunnelProvider, CloudflareTunnelProvider, FrpTunnelProvider | -| FR-MCP-016 | ✅ Complete | Program.cs (MapMcp), ModelContextProtocol.AspNetCore | -| FR-MCP-017 | ✅ Complete | Program.cs (UseWindowsService), Manage-McpService.ps1 | -| FR-MCP-018 | ✅ Complete | MarkerFileService, WorkspaceProcessManager | -| FR-MCP-019 | 🔀 Replaced | Replaced by FR-MCP-043 (single-app multi-tenant) | -| FR-MCP-020 | ✅ Complete | WorkspaceProcessManager (marker file writes) | -| FR-MCP-021 | ✅ Complete | WorkspaceController POST, WorkspaceService.InitAsync | -| FR-MCP-022 | ✅ Complete | ToolRegistryOptions, Program.cs (EnsureDefaultBucketsAsync) | -| FR-MCP-023 | ✅ Complete | RequirementsService, IRequirementsService, ICopilotClient | -| FR-MCP-024 | ✅ Complete | MarkdownSessionLogParser, SessionLogIngestor | -| FR-MCP-025 | ✅ Complete | WorkspaceProcessManager, WorkspaceConfigEntry, Program.cs | -| FR-LOC-001 | 🔲 Planned | — | -| TR-MCP-ARCH-001 | ✅ Complete | Core infrastructure | -| TR-MCP-DATA-001–003 | ✅ Complete | Storage and indexing | -| TR-MCP-CFG-001–002 | ✅ Complete | Configuration | -| TR-MCP-CFG-003 | ✅ Complete | WorkspaceConfigEntry schema + appsettings.json patch workflow | -| TR-MCP-INGEST-001–002 | ✅ Complete | Ingestion pipeline | -| TR-MCP-API-001 | ✅ Complete | REST API | -| TR-MCP-OPS-001 | ✅ Complete | Operational scripts | -| TR-MCP-WS-002–009 | ✅ Complete | Workspace management (TR-MCP-WS-006 obsolete) | -| TR-MCP-TR-001–003 | ✅ Complete | Tool registry | -| TR-MCP-SEC-001–002 | ✅ Complete | Security | -| TR-MCP-TUN-001–003 | ✅ Complete | Tunneling | -| TR-MCP-HTTP-001 | ✅ Complete | MCP transport | -| TR-MCP-SVC-001 | ✅ Complete | Windows service | -| TR-MCP-REQ-001 | ✅ Complete | AI requirements analysis | -| TR-MCP-REQ-002 | ✅ Complete | RequirementsDocumentService, RequirementsDocumentParser, RequirementsDocumentRenderer, RequirementsOptions | -| TR-MCP-REQ-003 | ✅ Complete | RequirementsController, FwhMcpTools, Program.cs (requirements DI/config) | -| TR-MCP-DRY-001 | ✅ Active directive | All code and scripts | -| TR-MCP-DOC-002 | ✅ Active directive | .github/copilot-instructions.md, AGENTS.md | -| TR-LOC-001 | 🔲 Planned | — | -| FR-MCP-026 | ✅ Complete | OidcAuthOptions, Program.cs (JWT Bearer + AgentManager policy), WorkspaceAuthMiddleware, AgentController, AuthConfigController, Setup-McpKeycloak.ps1, setup-mcp-keycloak.sh, McpServer.Director (AuthCommands, OidcAuthService, LoginDialog) | -| FR-MCP-027 | ✅ Complete | Program.cs (startup built-in seeding), AgentController, AgentService, AgentDefaults, AgentDefinitionEntity | -| FR-MCP-028 | 🔲 Planned | AgentController, AgentService, AgentWorkspaceEntity, AgentEventLogEntity, McpDbContext | -| FR-MCP-029 | ✅ Complete | McpServer.Cqrs (Dispatcher, CallContext, CorrelationId, Result, IPipelineBehavior) | -| FR-MCP-030 | ✅ Complete | McpServer.Director (Program, DirectorCommands, AuthCommands, InteractiveCommand, McpHttpClient, OidcAuthService, TokenCache, MainScreen, HealthScreen, AgentScreen, TodoScreen, SessionLogScreen, WorkspaceListScreen, WorkspacePolicyScreen, LoginDialog, ViewModelBinder) | -| FR-MCP-031 | 🔲 Planned | — | -| FR-MCP-032 | 🔲 Planned | — | -| FR-MCP-033 | ✅ Complete | WorkspaceController (POST /mcpserver/workspace/policy), WorkspacePolicyService, WorkspacePolicyDirectiveParser, McpServerMcpTools.workspace_policy_apply | -| FR-MCP-034 | ✅ Complete | IWorkspaceService, MarkerFileService, WorkspaceModels | -| FR-MCP-035 | ✅ Complete | templates/prompt-templates.yaml | -| FR-MCP-036 | ✅ Complete | AuditedCopilotClient, Program.cs (ICopilotClient decorator), McpStdioHost (ICopilotClient decorator), CopilotServiceCollectionExtensions | -| FR-MCP-037 | ✅ Complete | McpServer.Director (Program exec/list-viewmodels), McpServer.Cqrs.Mvvm (IViewModelRegistry) | -| FR-MCP-038 | ✅ Complete | templates/prompt-templates.yaml | -| FR-MCP-039 | ✅ Complete | Program.cs + McpStdioHost PostConfigure, appsettings.yaml RepoAllowlist, templates/prompt-templates.yaml | -| FR-MCP-040 | ✅ Complete | RequirementsController, RequirementsDocumentService, IRequirementsRepository | -| FR-MCP-041 | ✅ Complete | RequirementsController (/mcpserver/requirements/generate), RequirementsDocumentService, RequirementsDocumentRenderer | -| FR-MCP-042 | ✅ Complete | FwhMcpTools (requirements_* tools), RequirementsDocumentService | -| FR-MCP-043 | ✅ In Progress | WorkspaceResolutionMiddleware, WorkspaceContext, WorkspaceTokenService | -| FR-MCP-044 | ✅ In Progress | McpDbContext (global query filter), all entities (WorkspaceId) | -| TR-MCP-AUTH-001–003 | ✅ Complete | OidcAuthOptions, Program.cs (JwtBearer + AgentManager policy), WorkspaceAuthMiddleware, AgentController, Setup-McpKeycloak.ps1, setup-mcp-keycloak.sh, McpServer.Director (AuthCommands, OidcAuthService) | -| TR-MCP-AGENT-001–003 | ✅ Complete | AgentDefinitionEntity, AgentWorkspaceEntity, AgentEventLogEntity, McpDbContext, AgentDefaults, AgentService, AgentController, Program.cs (startup seeding), WorkspaceAppFactory (primary-only controller exposure) | -| TR-MCP-CQRS-001–005 | ✅ Complete | McpServer.Cqrs (Dispatcher, CallContext, CorrelationId, Result, IPipelineBehavior, ILoggerProvider) | -| TR-MCP-DIR-001–003 | ✅ Complete | McpServer.Director (System.CommandLine CLI, CQRS dispatch, OIDC auth, exec command, Terminal.Gui interactive mode) | -| TR-MCP-COMP-001–003 | ✅ Complete | IWorkspaceService, MarkerFileService | -| TR-MCP-AUDIT-001 | ✅ Complete | AuditedCopilotClient, Program.cs decorator wiring, McpStdioHost decorator wiring | -| TR-MCP-POL-001 | ✅ Complete | WorkspacePolicyService, WorkspacePolicyDirectiveParser, WorkspaceController policy endpoint, McpServerMcpTools.workspace_policy_apply | -| TR-MCP-DTO-001 | ✅ Complete | UnifiedSessionLogDto | -| TR-MCP-CTX-001 | ✅ Complete | Program.cs + McpStdioHost PostConfigure, appsettings.yaml RepoAllowlist, templates/prompt-templates.yaml | -| TR-MCP-MT-001 | ✅ Complete | WorkspaceContext, WorkspaceResolutionMiddleware | -| TR-MCP-MT-002 | ✅ Complete | WorkspaceResolutionMiddleware, WorkspaceTokenService | -| TR-MCP-MT-003 | ✅ Complete | McpDbContext (global query filter), all entities (WorkspaceId) | -| FR-MCP-045 | ✅ Complete | TodoController.MoveAsync, FwhMcpTools.TodoMove, TodoMoveRequest | -| FR-MCP-046 | ✅ Complete | VoiceController, VoiceConversationService, VoiceConversationOptions | -| FR-MCP-047 | ✅ Complete | DesktopProcessLauncher, NativeMethods | -| FR-MCP-048 | ✅ Complete | Program.cs (AddYamlFile), NetEscapades.Configuration.Yaml | -| TR-MCP-TODO-002 | ✅ Complete | TodoController, FwhMcpTools, TodoServiceResolver | -| TR-MCP-VOICE-001–003 | ✅ Complete | VoiceConversationService, VoiceController, VoiceConversationOptions | -| TR-MCP-CFG-004 | ✅ Complete | Program.cs, NetEscapades.Configuration.Yaml | -| TR-MCP-DESKTOP-001 | ✅ Complete | DesktopProcessLauncher, NativeMethods | -| FR-MCP-049 | ✅ Complete | PromptTemplateController, PromptTemplateService, PromptTemplateRenderer, TemplateClient, TemplatesScreen | -| TR-MCP-TPL-001 | ✅ Complete | PromptTemplateService, TemplateStorageOptions | -| TR-MCP-TPL-002 | ✅ Complete | PromptTemplateRenderer | -| TR-MCP-TPL-003 | ✅ Complete | PromptTemplateController, FwhMcpTools | -| TR-MCP-TPL-004 | ✅ Complete | TemplateMessages, \*TemplateQueryHandler, \*TemplateCommandHandler, TemplateApiClientAdapter, TemplateListViewModel, TemplateDetailViewModel, TemplatesScreen | -| FR-MCP-050 | ✅ Complete | IMarkerPromptProvider, FileMarkerPromptProvider, ITodoPromptProvider, TodoPromptProvider, PairingHtmlRenderer | -| TR-MCP-TPL-005 | ✅ Complete | IMarkerPromptProvider, FileMarkerPromptProvider, ITodoPromptProvider, TodoPromptProvider, PairingHtmlRenderer, templates/prompt-templates.yaml | -| FR-MCP-051 | 🔲 Planned | CopilotClientOptions, VoiceConversationOptions, AgentDefaults | -| TR-MCP-CFG-005 | 🔲 Planned | CopilotClientOptions, VoiceConversationOptions, AgentDefaults | -| FR-MCP-052 | ✅ Complete | AgentPoolOptions, AgentPoolDefinitionOptions, AgentPoolOptionsValidator, Program.cs (AgentPool registration), IAgentPoolService, AgentPoolService | -| FR-MCP-053 | ✅ Complete | AgentPoolService (queue lifecycle/dispatch), AgentPoolController (queue endpoints), TodoController queue enqueue endpoints | -| FR-MCP-054 | ✅ Complete | AgentPoolController, AgentPoolService (notification and per-job stream fan-out) | -| FR-MCP-055 | ✅ Complete | AgentPoolService (intent/context routing and default agent resolution), AgentPoolModels | -| FR-MCP-056 | ✅ Complete | PromptTemplateController, PromptTemplateService, PromptTemplateRenderer, AgentPoolService.ResolvePromptAsync, AgentPoolController queue/resolve | -| FR-MCP-057 | ✅ Complete | AgentPoolClient, Client.Models.AgentPoolModels, McpServerClient.AgentPool, AgentPoolScreen, MainScreen tab wiring | -| FR-MCP-058 | ✅ Complete | AgentPoolController SSE endpoints, AgentPoolService stream subscriptions, VoiceConversationService agent-session reuse/one-shot guard, VoiceController | -| TR-MCP-AGENT-004 | ✅ Complete | AgentPoolOptions, AgentPoolDefinitionOptions, AgentPoolOptionsValidator, Program.cs options validation/DI | -| TR-MCP-AGENT-005 | ✅ Complete | IAgentPoolService, AgentPoolService, AgentPoolController | -| TR-MCP-API-002 | ✅ Complete | AgentPoolController lifecycle/queue/resolve endpoints, AgentPoolService prompt/context routing | -| TR-MCP-API-003 | ✅ Complete | AgentPoolController notifications/jobs SSE, AgentPoolService notification + job stream channels | -| TR-MCP-TPL-006 | ✅ Complete | PromptTemplateController, PromptTemplateRenderer, AgentPoolService template/context prompt resolution | -| TR-MCP-VOICE-004 | ✅ Complete | VoiceConversationService pooled agent reuse + one-shot guard, AgentPoolService voice-runtime dispatch integration | -| TR-MCP-DIR-004 | ✅ Complete | AgentPoolClient, AgentPoolScreen, MainScreen tab integration, DirectorMcpContext typed client usage | -| FR-MCP-059 | 🔲 Planned | McpServer.Support.Mcp services/registries/managers/providers (DI SSOT state flow) | -| FR-MCP-060 | ✅ Complete | McpServer.UI.Core (Messages/Handlers/ViewModels), McpServer.Director (MainScreen, DirectorCommands/AuthCommands, ITabRegistry/DirectorTabRegistry), McpServer.Client adapters | -| FR-MCP-061 | ✅ Complete | TodoValidator, TodoService, SqliteTodoService, SessionLogIdentifierValidator, SessionLogController, SessionLogService | -| TR-MCP-DIR-005–008 | ✅ Complete | Endpoint-to-handler parity, ViewModel conventions, RBAC visibility/action mapping, declarative tab registry | -| TR-MCP-ARCH-002 | 🔲 Planned | DI lifetimes for state ownership, pull-notify flow via INotifyPropertyChanged, ActivatorUtilities remediation audit | -| TR-MCP-LOG-001 | ✅ Complete | Exception logging policy enforced across catch blocks (LogError/LogWarning) | -| TR-MCP-LOG-002 | ✅ Complete | TodoValidator, TodoService, SqliteTodoService, SessionLogIdentifierValidator, SessionLogController, SessionLogService | -| TEST-MCP-074 | ✅ Complete | TodoServiceTests, SqliteTodoServiceTests, SessionLogControllerTests, SessionLogServiceTests, MarkerFileServiceTests | -| FR-MCP-062 | ✅ Complete | IChangeEventBus, ChannelChangeEventBus, EventStreamController, mutation services/controllers/workspace process manager | -| TR-MCP-EVT-001 | ✅ Complete | ChannelChangeEventBus, IChangeEventBus, Program.cs (singleton registration) | -| TR-MCP-EVT-002 | ✅ Complete | TodoService, SqliteTodoService, SessionLogService, RepoFileService, ToolRegistryService, ToolBucketService, WorkspaceService, AgentService, RequirementsDocumentService, IngestionCoordinator, WorkspaceProcessManager | -| TR-MCP-EVT-003 | ✅ Complete | EventStreamController | -| TR-MCP-EVT-004 | ✅ Complete | ChangeEvent, ChangeEventActions, ChangeEventCategories | -| TR-MCP-EVT-005 | ✅ Complete | ChangeEventCategories, mutation publishers across workspace domains | -| TEST-MCP-075 | ✅ Complete | ChannelChangeEventBusTests | -| TEST-MCP-076 | ✅ Complete | TodoServiceTests, SqliteTodoServiceTests, SessionLogServiceTests, RepoFileServiceTests | -| TEST-MCP-077 | ✅ Complete | EventPublishingServiceTests | -| TEST-MCP-078 | ✅ Complete | EventStreamIntegrationTests | -| TEST-MCP-079 | ✅ Complete | EventStreamIntegrationTests | -| TEST-MCP-080 | ✅ Complete | EventStreamIntegrationTests (positive + non-matching category filter paths verified) | -| FR-MCP-063 | ✅ Complete | GitHubIntegrationOptions, FileGitHubWorkspaceTokenStore, GitHubController, GitHubCliService, ProcessRunner, GitHubClient | -| TR-MCP-GH-001 | ✅ Complete | GitHubIntegrationOptions, Program.cs, McpStdioHost, GitHubController | -| TR-MCP-GH-002 | ✅ Complete | IGitHubWorkspaceTokenStore, FileGitHubWorkspaceTokenStore, GitHubController | -| TR-MCP-GH-003 | ✅ Complete | IProcessRunner, ProcessRunner, GitHubCliService | -| TR-MCP-GH-004 | ✅ Complete | IGitHubCliService, GitHubCliService, GitHubController, McpServer.Client GitHub models/client | -| TEST-MCP-081 | ✅ Complete | GitHubControllerTests.AuthTokenEndpoints_RoundTrip | -| TEST-MCP-082 | ✅ Complete | GitHubControllerTests.OAuthConfig_AndAuthorizeUrlBehavior | -| TEST-MCP-083 | ✅ Complete | GitHubCliServiceTests.ListIssuesAsync_WithStoredWorkspaceToken_UsesProcessRunRequestOverride, FileGitHubWorkspaceTokenStoreTests | -| TEST-MCP-084 | ✅ Complete | GitHubCliServiceTests workflow run tests, GitHubControllerTests.ListWorkflowRuns_ReturnsOk, GitHubClientTests workflow/auth tests | -| TEST-MCP-085 | ✅ Complete | WorkspaceControllerTests.ApplyPolicy_ValidDirective_UpdatesWorkspaceBanList, WorkspaceControllerTests.ApplyPolicy_InvalidDirective_ReturnsBadRequest, WorkspacePolicyServiceTests | -| TEST-MCP-086 | ✅ Complete | AuditedCopilotClientTests, WorkspacePolicyDirectiveParserTests | -| TEST-MCP-087 | ✅ Complete | IngestionAllowlistContractTests.MarkerPromptTemplate_ContainsAvailableCapabilitiesSection | +# Requirements Matrix (MCP Server) + +Traceability policy: see `Requirements-Traceability-Policy.md`. + +| Requirement | Status | Source Files | +| --- | --- | --- | +| FR-SUPPORT-010 | ✅ Complete | ContextController, TodoController, RepoController, SessionLogController, McpServerMcpTools, HybridSearchService, Fts5SearchService, VectorIndexService | +| FR-MCP-001 | ✅ Complete | IngestionOptions, IOptions | +| FR-MCP-002 | ✅ Complete | TodoController, TodoService, SqliteTodoService | +| FR-MCP-003 | ✅ Complete | SessionLogController, SessionLogService | +| FR-MCP-004 | ✅ Complete | HybridSearchService, Fts5SearchService, VectorIndexService | +| FR-MCP-005 | ✅ Complete | GitHubController, GitHubCliService, IssueTodoSyncService | +| FR-MCP-006 | ✅ Complete | IngestionCoordinator, RepoIngestor, SessionLogIngestor | +| FR-MCP-007 | ✅ Complete | Program.cs, McpServerMcpTools, McpStdioHost | +| FR-MCP-008 | ✅ Complete | Dockerfile, docker-compose.mcp.yml | +| FR-MCP-009 | ✅ Complete | WorkspaceController, WorkspaceService | +| FR-MCP-011 | ✅ Complete | WorkspaceProcessManager | +| FR-MCP-012 | ✅ Complete | ToolRegistryController, ToolRegistryService, ToolBucketService | +| FR-MCP-013 | ✅ Complete | WorkspaceAuthMiddleware, WorkspaceTokenService, MarkerFileService | +| FR-MCP-014 | ✅ Complete | PairingHtml, PairingOptions, Program.cs (/pair) | +| FR-MCP-015 | ✅ Complete | NgrokTunnelProvider, CloudflareTunnelProvider, FrpTunnelProvider | +| FR-MCP-016 | ✅ Complete | Program.cs (MapMcp), ModelContextProtocol.AspNetCore | +| FR-MCP-017 | ✅ Complete | Program.cs (UseWindowsService), Manage-McpService.ps1 | +| FR-MCP-018 | ✅ Complete | MarkerFileService, WorkspaceProcessManager | +| FR-MCP-019 | 🔀 Replaced | Replaced by FR-MCP-043 (single-app multi-tenant) | +| FR-MCP-020 | ✅ Complete | WorkspaceProcessManager (marker file writes) | +| FR-MCP-021 | ✅ Complete | WorkspaceController POST, WorkspaceService.InitAsync | +| FR-MCP-022 | ✅ Complete | ToolRegistryOptions, Program.cs (EnsureDefaultBucketsAsync) | +| FR-MCP-023 | ✅ Complete | RequirementsService, IRequirementsService, ICopilotClient | +| FR-MCP-024 | ✅ Complete | MarkdownSessionLogParser, SessionLogIngestor | +| FR-MCP-025 | ✅ Complete | WorkspaceProcessManager, WorkspaceConfigEntry, Program.cs | +| FR-LOC-001 | 🔲 Planned | — | +| TR-MCP-ARCH-001 | ✅ Complete | Core infrastructure | +| TR-MCP-DATA-001–003 | ✅ Complete | Storage and indexing | +| TR-MCP-CFG-001–002 | ✅ Complete | Configuration | +| TR-MCP-CFG-003 | ✅ Complete | WorkspaceConfigEntry schema + appsettings.json patch workflow | +| TR-MCP-INGEST-001–002 | ✅ Complete | Ingestion pipeline | +| TR-MCP-API-001 | ✅ Complete | REST API | +| TR-MCP-OPS-001 | ✅ Complete | Operational scripts | +| TR-MCP-WS-002–009 | ✅ Complete | Workspace management (TR-MCP-WS-006 obsolete) | +| TR-MCP-TR-001–003 | ✅ Complete | Tool registry | +| TR-MCP-SEC-001–002 | ✅ Complete | Security | +| TR-MCP-TUN-001–003 | ✅ Complete | Tunneling | +| TR-MCP-HTTP-001 | ✅ Complete | MCP transport | +| TR-MCP-SVC-001 | ✅ Complete | Windows service | +| TR-MCP-REQ-001 | ✅ Complete | AI requirements analysis | +| TR-MCP-REQ-002 | ✅ Complete | RequirementsDocumentService, RequirementsDocumentParser, RequirementsDocumentRenderer, RequirementsOptions | +| TR-MCP-REQ-003 | ✅ Complete | RequirementsController, FwhMcpTools, Program.cs (requirements DI/config) | +| TR-MCP-DRY-001 | ✅ Active directive | All code and scripts | +| TR-MCP-DOC-002 | ✅ Active directive | .github/copilot-instructions.md, AGENTS.md | +| TR-LOC-001 | 🔲 Planned | — | +| FR-MCP-026 | ✅ Complete | OidcAuthOptions, Program.cs (JWT Bearer + AgentManager policy), WorkspaceAuthMiddleware, AgentController, AuthConfigController, Setup-McpKeycloak.ps1, setup-mcp-keycloak.sh, McpServer.Director (AuthCommands, OidcAuthService, LoginDialog) | +| FR-MCP-027 | ✅ Complete | Program.cs (startup built-in seeding), AgentController, AgentService, AgentDefaults, AgentDefinitionEntity | +| FR-MCP-028 | 🔲 Planned | AgentController, AgentService, AgentWorkspaceEntity, AgentEventLogEntity, McpDbContext | +| FR-MCP-029 | ✅ Complete | McpServer.Cqrs (Dispatcher, CallContext, CorrelationId, Result, IPipelineBehavior) | +| FR-MCP-030 | ✅ Complete | McpServer.Director (Program, DirectorCommands, AuthCommands, InteractiveCommand, McpHttpClient, OidcAuthService, TokenCache, MainScreen, HealthScreen, AgentScreen, TodoScreen, SessionLogScreen, WorkspaceListScreen, WorkspacePolicyScreen, LoginDialog, ViewModelBinder) | +| FR-MCP-031 | 🔲 Planned | — | +| FR-MCP-032 | 🔲 Planned | — | +| FR-MCP-033 | ✅ Complete | WorkspaceController (POST /mcpserver/workspace/policy), WorkspacePolicyService, WorkspacePolicyDirectiveParser, McpServerMcpTools.workspace_policy_apply | +| FR-MCP-034 | ✅ Complete | IWorkspaceService, MarkerFileService, WorkspaceModels | +| FR-MCP-035 | ✅ Complete | templates/prompt-templates.yaml | +| FR-MCP-036 | ✅ Complete | AuditedCopilotClient, Program.cs (ICopilotClient decorator), McpStdioHost (ICopilotClient decorator), CopilotServiceCollectionExtensions | +| FR-MCP-037 | ✅ Complete | McpServer.Director (Program exec/list-viewmodels), McpServer.Cqrs.Mvvm (IViewModelRegistry) | +| FR-MCP-038 | ✅ Complete | templates/prompt-templates.yaml | +| FR-MCP-039 | ✅ Complete | Program.cs + McpStdioHost PostConfigure, appsettings.yaml RepoAllowlist, templates/prompt-templates.yaml | +| FR-MCP-040 | ✅ Complete | RequirementsController, RequirementsDocumentService, IRequirementsRepository | +| FR-MCP-041 | ✅ Complete | RequirementsController (/mcpserver/requirements/generate), RequirementsDocumentService, RequirementsDocumentRenderer | +| FR-MCP-042 | ✅ Complete | FwhMcpTools (requirements_* tools), RequirementsDocumentService | +| FR-MCP-043 | ✅ In Progress | WorkspaceResolutionMiddleware, WorkspaceContext, WorkspaceTokenService | +| FR-MCP-044 | ✅ In Progress | McpDbContext (global query filter), all entities (WorkspaceId) | +| TR-MCP-AUTH-001–003 | ✅ Complete | OidcAuthOptions, Program.cs (JwtBearer + AgentManager policy), WorkspaceAuthMiddleware, AgentController, Setup-McpKeycloak.ps1, setup-mcp-keycloak.sh, McpServer.Director (AuthCommands, OidcAuthService) | +| TR-MCP-AGENT-001–003 | ✅ Complete | AgentDefinitionEntity, AgentWorkspaceEntity, AgentEventLogEntity, McpDbContext, AgentDefaults, AgentService, AgentController, Program.cs (startup seeding), WorkspaceAppFactory (primary-only controller exposure) | +| TR-MCP-CQRS-001–005 | ✅ Complete | McpServer.Cqrs (Dispatcher, CallContext, CorrelationId, Result, IPipelineBehavior, ILoggerProvider) | +| TR-MCP-DIR-001–003 | ✅ Complete | McpServer.Director (System.CommandLine CLI, CQRS dispatch, OIDC auth, exec command, Terminal.Gui interactive mode) | +| TR-MCP-COMP-001–003 | ✅ Complete | IWorkspaceService, MarkerFileService | +| TR-MCP-AUDIT-001 | ✅ Complete | AuditedCopilotClient, Program.cs decorator wiring, McpStdioHost decorator wiring | +| TR-MCP-POL-001 | ✅ Complete | WorkspacePolicyService, WorkspacePolicyDirectiveParser, WorkspaceController policy endpoint, McpServerMcpTools.workspace_policy_apply | +| TR-MCP-DTO-001 | ✅ Complete | UnifiedSessionLogDto | +| TR-MCP-CTX-001 | ✅ Complete | Program.cs + McpStdioHost PostConfigure, appsettings.yaml RepoAllowlist, templates/prompt-templates.yaml | +| TR-MCP-MT-001 | ✅ Complete | WorkspaceContext, WorkspaceResolutionMiddleware | +| TR-MCP-MT-002 | ✅ Complete | WorkspaceResolutionMiddleware, WorkspaceTokenService | +| TR-MCP-MT-003 | ✅ Complete | McpDbContext (global query filter), all entities (WorkspaceId) | +| FR-MCP-045 | ✅ Complete | TodoController.MoveAsync, FwhMcpTools.TodoMove, TodoMoveRequest | +| FR-MCP-046 | ✅ Complete | VoiceController, VoiceConversationService, VoiceConversationOptions | +| FR-MCP-047 | ✅ Complete | DesktopProcessLauncher, NativeMethods, DesktopLaunchService, DesktopController, FwhMcpTools.DesktopLaunch | +| FR-MCP-048 | ✅ Complete | Program.cs (AddYamlFile), NetEscapades.Configuration.Yaml | +| TR-MCP-TODO-002 | ✅ Complete | TodoController, FwhMcpTools, TodoServiceResolver | +| TR-MCP-VOICE-001–003 | ✅ Complete | VoiceConversationService, VoiceController, VoiceConversationOptions | +| TR-MCP-CFG-004 | ✅ Complete | Program.cs, NetEscapades.Configuration.Yaml | +| TR-MCP-DESKTOP-001 | ✅ Complete | DesktopProcessLauncher, NativeMethods, DesktopLaunchService, DesktopController, FwhMcpTools.DesktopLaunch | +| FR-MCP-049 | ✅ Complete | PromptTemplateController, PromptTemplateService, PromptTemplateRenderer, TemplateClient, TemplatesScreen | +| TR-MCP-TPL-001 | ✅ Complete | PromptTemplateService, TemplateStorageOptions | +| TR-MCP-TPL-002 | ✅ Complete | PromptTemplateRenderer | +| TR-MCP-TPL-003 | ✅ Complete | PromptTemplateController, FwhMcpTools | +| TR-MCP-TPL-004 | ✅ Complete | TemplateMessages, \*TemplateQueryHandler, \*TemplateCommandHandler, TemplateApiClientAdapter, TemplateListViewModel, TemplateDetailViewModel, TemplatesScreen | +| FR-MCP-050 | ✅ Complete | IMarkerPromptProvider, FileMarkerPromptProvider, ITodoPromptProvider, TodoPromptProvider, PairingHtmlRenderer | +| TR-MCP-TPL-005 | ✅ Complete | IMarkerPromptProvider, FileMarkerPromptProvider, ITodoPromptProvider, TodoPromptProvider, PairingHtmlRenderer, templates/prompt-templates.yaml | +| FR-MCP-051 | 🔲 Planned | CopilotClientOptions, VoiceConversationOptions, AgentDefaults | +| TR-MCP-CFG-005 | 🔲 Planned | CopilotClientOptions, VoiceConversationOptions, AgentDefaults | +| FR-MCP-052 | ✅ Complete | AgentPoolOptions, AgentPoolDefinitionOptions, AgentPoolOptionsValidator, Program.cs (AgentPool registration), IAgentPoolService, AgentPoolService | +| FR-MCP-053 | ✅ Complete | AgentPoolService (queue lifecycle/dispatch), AgentPoolController (queue endpoints), TodoController queue enqueue endpoints | +| FR-MCP-054 | ✅ Complete | AgentPoolController, AgentPoolService (notification and per-job stream fan-out) | +| FR-MCP-055 | ✅ Complete | AgentPoolService (intent/context routing and default agent resolution), AgentPoolModels | +| FR-MCP-056 | ✅ Complete | PromptTemplateController, PromptTemplateService, PromptTemplateRenderer, AgentPoolService.ResolvePromptAsync, AgentPoolController queue/resolve | +| FR-MCP-057 | ✅ Complete | AgentPoolClient, Client.Models.AgentPoolModels, McpServerClient.AgentPool, AgentPoolScreen, MainScreen tab wiring | +| FR-MCP-058 | ✅ Complete | AgentPoolController SSE endpoints, AgentPoolService stream subscriptions, VoiceConversationService agent-session reuse/one-shot guard, VoiceController | +| TR-MCP-AGENT-004 | ✅ Complete | AgentPoolOptions, AgentPoolDefinitionOptions, AgentPoolOptionsValidator, Program.cs options validation/DI | +| TR-MCP-AGENT-005 | ✅ Complete | IAgentPoolService, AgentPoolService, AgentPoolController | +| TR-MCP-API-002 | ✅ Complete | AgentPoolController lifecycle/queue/resolve endpoints, AgentPoolService prompt/context routing | +| TR-MCP-API-003 | ✅ Complete | AgentPoolController notifications/jobs SSE, AgentPoolService notification + job stream channels | +| TR-MCP-TPL-006 | ✅ Complete | PromptTemplateController, PromptTemplateRenderer, AgentPoolService template/context prompt resolution | +| TR-MCP-VOICE-004 | ✅ Complete | VoiceConversationService pooled agent reuse + one-shot guard, AgentPoolService voice-runtime dispatch integration | +| TR-MCP-DIR-004 | ✅ Complete | AgentPoolClient, AgentPoolScreen, MainScreen tab integration, DirectorMcpContext typed client usage | +| FR-MCP-059 | 🔲 Planned | McpServer.Support.Mcp services/registries/managers/providers (DI SSOT state flow) | +| FR-MCP-060 | ✅ Complete | McpServer.UI.Core (Messages/Handlers/ViewModels), McpServer.Director (MainScreen, DirectorCommands/AuthCommands, ITabRegistry/DirectorTabRegistry), McpServer.Client adapters | +| FR-MCP-061 | ✅ Complete | TodoValidator, TodoService, SqliteTodoService, TodoCreationService, SessionLogIdentifierValidator, SessionLogController, SessionLogService | +| TR-MCP-DIR-005–008 | ✅ Complete | Endpoint-to-handler parity, ViewModel conventions, RBAC visibility/action mapping, declarative tab registry | +| TR-MCP-ARCH-002 | 🔲 Planned | DI lifetimes for state ownership, pull-notify flow via INotifyPropertyChanged, ActivatorUtilities remediation audit | +| TR-MCP-LOG-001 | ✅ Complete | Exception logging policy enforced across catch blocks (LogError/LogWarning) | +| TR-MCP-LOG-002 | ✅ Complete | TodoValidator, TodoService, SqliteTodoService, SessionLogIdentifierValidator, SessionLogController, SessionLogService | +| TEST-MCP-074 | ✅ Complete | TodoServiceTests, SqliteTodoServiceTests, SessionLogControllerTests, SessionLogServiceTests, MarkerFileServiceTests | +| FR-MCP-062 | ✅ Complete | IChangeEventBus, ChannelChangeEventBus, EventStreamController, mutation services/controllers/workspace process manager | +| TR-MCP-EVT-001 | ✅ Complete | ChannelChangeEventBus, IChangeEventBus, Program.cs (singleton registration) | +| TR-MCP-EVT-002 | ✅ Complete | TodoService, SqliteTodoService, SessionLogService, RepoFileService, ToolRegistryService, ToolBucketService, WorkspaceService, AgentService, RequirementsDocumentService, IngestionCoordinator, WorkspaceProcessManager | +| TR-MCP-EVT-003 | ✅ Complete | EventStreamController | +| TR-MCP-EVT-004 | ✅ Complete | ChangeEvent, ChangeEventActions, ChangeEventCategories | +| TR-MCP-EVT-005 | ✅ Complete | ChangeEventCategories, mutation publishers across workspace domains | +| TEST-MCP-075 | ✅ Complete | ChannelChangeEventBusTests | +| TEST-MCP-076 | ✅ Complete | TodoServiceTests, SqliteTodoServiceTests, SessionLogServiceTests, RepoFileServiceTests | +| TEST-MCP-077 | ✅ Complete | EventPublishingServiceTests | +| TEST-MCP-078 | ✅ Complete | EventStreamIntegrationTests | +| TEST-MCP-079 | ✅ Complete | EventStreamIntegrationTests | +| TEST-MCP-080 | ✅ Complete | EventStreamIntegrationTests (positive + non-matching category filter paths verified) | +| FR-MCP-063 | ✅ Complete | GitHubIntegrationOptions, FileGitHubWorkspaceTokenStore, GitHubController, GitHubCliService, ProcessRunner, GitHubClient | +| TR-MCP-GH-001 | ✅ Complete | GitHubIntegrationOptions, Program.cs, McpStdioHost, GitHubController | +| TR-MCP-GH-002 | ✅ Complete | IGitHubWorkspaceTokenStore, FileGitHubWorkspaceTokenStore, GitHubController | +| TR-MCP-GH-003 | ✅ Complete | IProcessRunner, ProcessRunner, GitHubCliService | +| TR-MCP-GH-004 | ✅ Complete | IGitHubCliService, GitHubCliService, GitHubController, McpServer.Client GitHub models/client | +| TEST-MCP-081 | ✅ Complete | GitHubControllerTests.AuthTokenEndpoints_RoundTrip | +| TEST-MCP-082 | ✅ Complete | GitHubControllerTests.OAuthConfig_AndAuthorizeUrlBehavior | +| TEST-MCP-083 | ✅ Complete | GitHubCliServiceTests.ListIssuesAsync_WithStoredWorkspaceToken_UsesProcessRunRequestOverride, FileGitHubWorkspaceTokenStoreTests | +| TEST-MCP-084 | ✅ Complete | GitHubCliServiceTests workflow run tests, GitHubControllerTests.ListWorkflowRuns_ReturnsOk, GitHubClientTests workflow/auth tests | +| TEST-MCP-085 | ✅ Complete | WorkspaceControllerTests.ApplyPolicy_ValidDirective_UpdatesWorkspaceBanList, WorkspaceControllerTests.ApplyPolicy_InvalidDirective_ReturnsBadRequest, WorkspacePolicyServiceTests | +| TEST-MCP-086 | ✅ Complete | AuditedCopilotClientTests, WorkspacePolicyDirectiveParserTests | +| TEST-MCP-087 | ✅ Complete | IngestionAllowlistContractTests.MarkerPromptTemplate_ContainsAvailableCapabilitiesSection | +| FR-MCP-065 | ✅ Complete | ContextController (ingest-website), IngestionCoordinator.IngestWebsiteAsync, WebsiteIngestor, FwhMcpTools.context_ingest_website, ContextClient.IngestWebsiteAsync | +| TR-MCP-INGEST-003 | ✅ Complete | WebsiteIngestor, IngestionOptions website limits, Program/McpStdioHost HttpClient registration, IngestionCoordinator website path | +| TEST-MCP-088 | ✅ Complete | WebsiteIngestorTests, ContextControllerTests (ingest-website), McpTransportTests (context_ingest_website), ContextClientTests.IngestWebsiteAsync_PostsTypedRequest | +| FR-MCP-066 | ✅ Complete | `McpServer.McpAgent` (`ServiceCollectionExtensions`, `McpAgentOptions`, `Hosting/*`, `PowerShellSessions/*`, `SessionLog/*`, `Todo/*`), `McpServer.Client` (`McpServerClient`, `RepoClient`, `DesktopClient`), `McpServer.McpAgent.SampleHost` (`Program.cs`, `SampleHostPreviewFactory.cs`) | +| TR-MCP-AGENT-006 | ✅ Complete | `ServiceCollectionExtensions`, `McpAgentOptions`, `McpAgentOptionsValidator`, `IMcpHostedAgent`, `IMcpHostedAgentFactory`, `McpHostedAgent`, `McpHostedAgentRegistration` | +| TR-MCP-AGENT-007 | ✅ Complete | `SessionLogWorkflow`, `SessionLogWorkflowContext`, `SessionLogTurnContext`, `TodoWorkflow`, `IMcpHostedAgent.PowerShellSessions`, `IHostedPowerShellSessionManager`, `McpHostedAgentToolAdapter`, `HostedPowerShellSessionManager`, `HostedPowerShellSessionHost`, `PowerShellSessionCreateResult`, `PowerShellSessionCommandResult`, `PowerShellSessionCloseResult`, `McpServerClient`, `RepoClient`, `DesktopClient`, `McpSessionIdentifierFactory` | +| TEST-MCP-089 | ✅ Complete | `HostedAgentWorkflowIntegrationTests`, `McpHostedAgentAdapterTests`, `DesktopClientTests`, `DesktopControllerTests`, `SessionLogWorkflowTests`, `TodoWorkflowTests`, `ServiceCollectionExtensionsTests`, `PowerShellSessions_ExecuteInteractiveCommand_PreservesHostLocalSessionState` | +| FR-MCP-067 | 🔲 Planned | — | +| TR-MCP-HTTP-002 | 🔲 Planned | — | +| TEST-MCP-090 | 🔲 Planned | — | +| FR-MCP-068 | ✅ Complete | ConfigurationController, AppSettingsFileService, Program.cs (JWT Bearer auth), WorkspaceController | +| TR-MCP-CFG-006 | ✅ Complete | ConfigurationController, AppSettingsFileService, Program.cs (JWT Bearer auth), WorkspaceController | +| TEST-MCP-091 | ✅ Complete | ConfigurationControllerTests, AppSettingsFileServiceTests, ConfigurationAuthorizationPolicyTests | +| FR-MCP-069 | ✅ Complete | TodoCreationService, GitHubCliService, TodoController, FwhMcpTools, VoiceConversationService | +| TR-MCP-TODO-003 | ✅ Complete | TodoCreationService, TodoValidator, TodoController, FwhMcpTools, VoiceConversationService, TodoService, SqliteTodoService | +| TR-MCP-GH-005 | ✅ Complete | WorkspaceServiceAccessor, GitHubCliService, ProcessRunRequest | +| TEST-MCP-092 | ✅ Complete | TodoCreationServiceTests, TodoControllerTests | +| TEST-MCP-093 | ✅ Complete | GitHubCliServiceTests | +| FR-MCP-070 | ✅ Complete | TodoUpdateService, IssueTodoSyncService, TodoController, FwhMcpTools, VoiceConversationService | +| TR-MCP-TODO-004 | ✅ Complete | TodoUpdateService, TodoController, FwhMcpTools, VoiceConversationService | +| TR-MCP-GH-006 | ✅ Complete | IssueTodoSyncService, GitHubCliService | +| TEST-MCP-094 | ✅ Complete | TodoUpdateServiceTests, IssueTodoSyncServiceTests | +| FR-MCP-071 | ✅ Complete | IssueTodoSyncService, TodoUpdateService, GitHubController, TodoController | +| TR-MCP-GH-007 | ✅ Complete | IssueTodoSyncService | +| TEST-MCP-095 | ✅ Complete | IssueTodoSyncServiceTests, IssueTodoGitHubRoundTripIntegrationTests | +| FR-MCP-072 | ✅ Complete | SqliteTodoService, TodoYamlFileSerializer, TodoController, TodoClient, McpServerMcpTools, TodoServiceFactory | +| TR-MCP-TODO-005 | ✅ Complete | SqliteTodoService, TodoYamlFileSerializer, TodoServiceFactory, TodoStorageOptions, McpInstanceResolver, appsettings*.yaml | +| TR-MCP-TODO-006 | ✅ Complete | ITodoService, ITodoStore, SqliteTodoService, TodoController, McpServerMcpTools, TodoClient, TodoModels, TodoCreationService, TodoUpdateService | +| TEST-MCP-096 | ✅ Complete | SqliteTodoServiceTests, MixedTodoStorageIsolationTests | +| TEST-MCP-097 | ✅ Complete | SqliteTodoServiceTests, TodoControllerTests, TodoClientTests, IntegrationTests Controllers.TodoControllerTests | + diff --git a/docs/Project/TODO.yaml b/docs/Project/TODO.yaml index 8fba8f8c..51321f57 100644 --- a/docs/Project/TODO.yaml +++ b/docs/Project/TODO.yaml @@ -1,2364 +1,2715 @@ -requirements-management: - high-priority: - - id: REQ-MGMT-001 - title: Requirements Management Feature - CRUD + document generation endpoints - estimate: 4-6 days - note: 'High priority - builds on FR-MCP-023 (AI requirements analysis). This TODO intentionally uses a non-FR ID because FR-MCP-026 was reassigned to OIDC authentication in the requirements docs. Provides a first-class Requirements Management subsystem: in-memory model loaded from the four canonical docs, full CRUD for FR/TR/TEST entries, and REST + MCP tool endpoints to regenerate any or all four documents in their exact established Markdown format (individually or as a ZIP).' - done: true - completed: 2026-02-26 - description: - - 'Create a RequirementsManagementController with REST endpoints for CRUD on Functional Requirements (FR), Technical Requirements (TR), and Testing Requirements (TEST) entries, backed by the four canonical files: Functional-Requirements.md, Technical-Requirements.md, Testing-Requirements.md, and TR-per-FR-Mapping.md.' - - Add a document generation endpoint GET /mcpserver/requirements/generate?doc={functional|technical| testing|mapping|all} that renders requirements documents as Markdown (text/markdown) matching the exact established structure, or as a ZIP archive when doc=all. - - 'Expose five MCP tools: requirements_generate, requirements_list, requirements_create, requirements_update, requirements_delete - enabling AI agents to manage requirements and generate up-to-date documentation directly from a conversation.' - - On startup, parse all four document files into a strongly-typed in-memory model and keep it synchronized with file writes on every mutating operation. - done-summary: Implemented requirements document parsing/rendering service, REST CRUD + generate endpoints, STDIO MCP tools, DI/config wiring, and focused service/controller tests. - technical-details: - - 'New project component: RequirementsManagementController at src/McpServer.Support.Mcp/Controllers/RequirementsController.cs' - - 'RequirementsDocumentService - parses Functional-Requirements.md (## FR-{ID}\n\n{title}\n\n{body}), Technical-Requirements.md (## TR-{ID}\n\n**{title}** - {body}), Testing-Requirements.md (bullet list: - TEST-{ID}: {condition} format), and TR-per-FR-Mapping.md (Markdown table). Exposes IRequirementsDocumentService with typed CRUD and generation methods.' - - IRequirementsRepository - file-backed persistence using SemaphoreSlim for write serialization. Each mutating call updates the in-memory model then atomically writes the affected file via File.WriteAllTextAsync to a temp path followed by File.Replace (atomic swap). - - RequirementsDocumentRenderer - RenderFunctional(), RenderTechnical(), RenderTesting(), RenderMapping(), RenderAll(). RenderAll() uses System.IO.Compression.ZipArchive to produce a single in-memory ZIP containing all four files with their canonical filenames. - - 'Sub-resources: POST/GET /mcpserver/requirements/fr, GET/PUT/DELETE /mcpserver/requirements/fr/{id}; same pattern for /tr/{id} and /test/{id}. GET /mcpserver/requirements/mapping for the full table. GET /mcpserver/requirements/generate?doc= for document output.' - - 'MCP tools (added to McpServerMcpTools.cs): requirements_generate(doc), requirements_list(type), requirements_create(type, id, title, body), requirements_update(type, id, title?, body?), requirements_delete(type, id).' - - 'Document file paths resolved relative to RepoRoot via IOptions. Default paths: docs/Project/Functional-Requirements.md, docs/Project/Technical-Requirements.md, docs/Project/Testing-Requirements.md, docs/Project/TR-per-FR-Mapping.md. Configurable via Mcp:Requirements:* config section.' - - All public types require XML doc comments (CS1591 enforced as error in this repo). - - ApiKeyAuthFilter is no longer used; all /mcpserver/* routes are protected by WorkspaceAuthMiddleware at the pipeline level. No per-controller auth attributes needed. - functional-requirements: - - 'FR-MCP-040: Server shall support CRUD for FR, TR, and TEST requirement entries stored in the four canonical project documentation files.' - - 'FR-MCP-041: Server shall expose a document generation endpoint rendering any or all four requirements documents in their established Markdown format.' - - 'FR-MCP-042: Server shall expose MCP tools for requirements CRUD and document generation usable by AI agents.' - technical-requirements: - - 'TR-MCP-REQ-002: RequirementsDocumentService parses all four files into a typed in-memory model on startup and keeps files synchronized on mutation.' - - 'TR-MCP-REQ-002: RequirementsDocumentRenderer produces Markdown output matching exact heading style and bullet/table structure of each canonical document.' - - 'TR-MCP-REQ-002: doc=all returns application/zip containing all four files; individual doc values return text/markdown.' - - 'TR-MCP-REQ-002: Write operations use atomic file swap (temp + File.Replace) and SemaphoreSlim serialization to prevent corruption.' - implementation-tasks: - - task: '[Phase 1 - Model] Define FrEntry(Id, Title, Body), TrEntry(Id, Title, Body), TestEntry(Id, Condition), FrTrMapping(FrId, TrIds) records in Requirements/Models/' - done: true - - task: '[Phase 1 - Model] Define IRequirementsRepository with GetAllFrAsync, GetFrAsync, AddFrAsync, UpdateFrAsync, DeleteFrAsync (same for Tr/Test/Mapping)' - done: true - - task: '[Phase 1 - Model] Define IRequirementsDocumentService extending IRequirementsRepository plus GenerateDocumentAsync(RequirementsDocType), GenerateAllAsync()' - done: true - - task: '[Phase 2 - Parsing] Implement FunctionalRequirementsParser: regex ## (FR-[A-Z]+-\d+)\s+\n+\*\*?(.+?)\*\*?\s+-?\s+([\s\S]+?)(?=\n## |\z) to extract Id/Title/Body' - done: true - - task: '[Phase 2 - Parsing] Implement TechnicalRequirementsParser: same ## heading pattern, bold title with em-dash separator convention' - done: true - - task: '[Phase 2 - Parsing] Implement TestingRequirementsParser: bullet list pattern - (TEST-[A-Z]+-\d+): (.+) per line' - done: true - - task: '[Phase 2 - Parsing] Implement MappingParser: Markdown table rows | FR-id | TR-ids | with comma-separated TR IDs per cell' - done: true - - task: '[Phase 3 - Renderer] Implement RequirementsDocumentRenderer.RenderFunctional(IEnumerable): # Functional Requirements (MCP Server)\n\n## {Id}\n\n{Title}\n\n{Body}\n\n' - done: true - - task: '[Phase 3 - Renderer] Implement RenderTechnical(IEnumerable): ## {Id}\n\n**{Title}** - {Body}\n\n' - done: true - - task: '[Phase 3 - Renderer] Implement RenderTesting(IEnumerable): # Testing Requirements (MCP Server)\n\n- {Id}: {Condition}\n per entry' - done: true - - task: '[Phase 3 - Renderer] Implement RenderMapping(IEnumerable): | FR | Primary TRs |\n| --- | --- |\n| {FrId} | {TrIds joined by ", "} |' - done: true - - task: '[Phase 3 - Renderer] Implement RenderAll(): create MemoryStream + ZipArchive, add all four rendered documents as entries with canonical filenames' - done: true - - task: '[Phase 4 - Service] Implement RequirementsDocumentService: constructor reads all four files via IRequirementsRepository, populates _frEntries/_trEntries/_testEntries/_mappings ConcurrentDictionary' - done: true - - task: '[Phase 4 - Service] Implement atomic file write: write to {path}.tmp, then File.Replace(tmp, target, backup: null) under SemaphoreSlim' - done: true - - task: '[Phase 4 - Service] Implement GenerateDocumentAsync(RequirementsDocType): switch on enum, call appropriate renderer, return (content, mimeType) tuple' - done: true - - task: '[Phase 4 - Service] Implement GenerateAllAsync(): call RenderAll(), return MemoryStream' - done: true - - task: '[Phase 5 - Controller] Implement RequirementsController: GET/POST /mcpserver/requirements/fr, GET/PUT/DELETE /mcpserver/requirements/fr/{id} (same pattern for /tr and /test)' - done: true - - task: '[Phase 5 - Controller] Add GET /mcpserver/requirements/generate?doc= endpoint: parse enum, call GenerateDocumentAsync or GenerateAllAsync, set Content-Disposition attachment header' - done: true - - task: '[Phase 5 - Controller] Add GET /mcpserver/requirements/mapping and PUT /mcpserver/requirements/mapping/{frId} for the TR-per-FR table' - done: true - - task: '[Phase 5 - Controller] Auth is handled by WorkspaceAuthMiddleware at the pipeline level - no per-action attributes needed' - done: true - - task: '[Phase 5 - Controller] Add full XML doc comments on all controller actions and parameters' - done: true - - task: '[Phase 6 - MCP Tools] Add [McpServerTool] requirements_list(string type) to McpServerMcpTools.cs: returns JSON array of matching entries' - done: true - - task: '[Phase 6 - MCP Tools] Add [McpServerTool] requirements_generate(string doc) to McpServerMcpTools.cs: returns Markdown string for specified doc type (all returns concatenated with --- separators)' - done: true - - task: '[Phase 6 - MCP Tools] Add [McpServerTool] requirements_create(string type, string id, string title, string body) with XML docs' - done: true - - task: '[Phase 6 - MCP Tools] Add [McpServerTool] requirements_update(string type, string id, string? title, string? body) with XML docs' - done: true - - task: '[Phase 6 - MCP Tools] Add [McpServerTool] requirements_delete(string type, string id) with XML docs' - done: true - - task: '[Phase 7 - Config] Add RequirementsOptions bound to Mcp:Requirements with FunctionalRequirementsPath, TechnicalRequirementsPath, TestingRequirementsPath, MappingPath (all defaulting to docs/Project/*.md relative to RepoRoot)' - done: true - - task: '[Phase 7 - Config] Register IRequirementsDocumentService, IRequirementsRepository in Program.cs DI' - done: true - - task: '[Phase 8 - Tests] Unit tests for each parser: given canonical file content, when parsed, then all entries are correctly extracted with right IDs, titles, and bodies' - done: true - - task: '[Phase 8 - Tests] Unit tests for each renderer: given typed entries, when rendered, then output matches expected Markdown structure exactly (heading level, bold format, bullet syntax)' - done: true - - task: '[Phase 8 - Tests] Integration test: POST /mcpserver/requirements/fr creates entry → GET /mcpserver/requirements/generate?doc=functional contains new entry → DELETE removes it → generate no longer contains it' - done: true - - task: '[Phase 8 - Tests] Integration test: GET /mcpserver/requirements/generate?doc=all returns 200 application/zip with four entries matching canonical filenames' - done: true - - task: '[Phase 8 - Tests] Test atomic write: simulate concurrent mutations, verify file integrity after all complete' - done: true -staging-and-infrastructure: - high-priority: - - id: nuget-client-lib - title: Create REST client library and NuGet package with publish pipeline - estimate: 3-5 days - note: 'Implemented: McpServer.Client library with 8 sub-clients covering all 52+ API endpoints, typed DTOs, exception hierarchy, DI integration, factory pattern, 35 unit tests, CI pipeline with NuGet publish (main→nuget.org, other→GitHub Packages).' - done: true - description: - - Create a typed REST client library (McpServer.Client) wrapping all 52 MCP Server API endpoints across 8 controllers - - Package as SharpNinja.McpServer.Client for nuget.org distribution - - 'Add publish-to-NuGet stage in CI pipeline: main branch publishes to nuget.org, develop/other branches publish to GitHub NuGet repository' - - Include DI extension method AddMcpServerClient() for easy ASP.NET Core integration - - Full XML-doc coverage and README with usage examples - technical-details: - - 'Target frameworks: net9.0;netstandard2.0 (multi-target for broad compatibility)' - - 'Dependencies: System.Net.Http.Json, System.Text.Json, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.Http, Microsoft.Extensions.Options' - - 'Project path: src/McpServer.Client/McpServer.Client.csproj' - - 'PackageId: SharpNinja.McpServer.Client' - - 'Version source: .version file + -preview.{buildnumber} suffix for non-main branches' - - SourceLink enabled via Directory.Build.props (already configured for deterministic builds) - - HttpClient-based with IHttpClientFactory integration for proper connection pooling - - System.Text.Json source generators for AOT-compatible serialization (McpJsonContext) - - All response types use records for immutability - - CancellationToken on every async method - - Nullable reference types enabled - - API key passed via X-Api-Key header (configurable via McpServerClientOptions) - functional-requirements: - - 'FR-01: Client must expose typed methods for all 52 API endpoints across 8 controllers' - - 'FR-02: All methods must be async and accept CancellationToken' - - 'FR-03: Client must support API key authentication for protected endpoints (tools write operations)' - - 'FR-04: Client must support configurable base URL for multi-instance deployments' - - 'FR-05: Client must deserialize all response types to strongly-typed DTOs' - - 'FR-06: Client must throw typed exceptions for HTTP error responses (400→McpValidationException with errors dict, 404→McpNotFoundException, 401→McpUnauthorizedException, 500→McpServerException)' - - 'FR-07: Client must support both DI (AddMcpServerClient) and manual instantiation (McpServerClientFactory)' - - 'FR-08: Package must work on net9.0 and netstandard2.0 consumers' - - 'FR-09: CI must publish stable packages to nuget.org from main branch only' - - 'FR-10: CI must publish preview packages to GitHub Packages from develop/feature branches' - technical-requirements: - - 'TR-01: Multi-target net9.0;netstandard2.0 in csproj' - - 'TR-02: Use IHttpClientFactory pattern for connection pooling and lifecycle management' - - 'TR-03: System.Text.Json source generators for AOT compatibility (JsonSerializerContext)' - - 'TR-04: All public types must have XML documentation comments' - - 'TR-05: Enable nullable reference types' - - 'TR-06: SourceLink enabled for debugger source stepping' - - 'TR-07: Deterministic build (already in Directory.Build.props)' - - 'TR-08: Package version derived from .version file + CI build number for pre-release suffix' - - 'TR-09: GitHub Actions job uses conditional steps for NuGet source selection' - - 'TR-10: NUGET_API_KEY stored as GitHub repository secret' - - 'TR-11: GitHub Packages auth uses built-in GITHUB_TOKEN' - - 'TR-12: --skip-duplicate flag on nuget push to handle re-runs gracefully' - - 'TR-13: Unit test coverage >90% on client methods using mocked HttpMessageHandler' - - 'TR-14: Integration tests gated behind MCP_TEST_BASE_URL environment variable' - implementation-tasks: - - task: '[Phase 1 - Scaffolding] Create src/McpServer.Client/ directory and McpServer.Client.csproj with multi-target net9.0;netstandard2.0' - done: false - - task: '[Phase 1 - Scaffolding] Add NuGet metadata: PackageId=SharpNinja.McpServer.Client, Authors, Description, PackageProjectUrl, RepositoryUrl, PackageTags=mcp model-context-protocol rest-client, PackageReadmeFile=README.md, PackageLicenseExpression=MIT' - done: false - - task: '[Phase 1 - Scaffolding] Add project to McpServer.sln in src/ solution folder' - done: false - - task: '[Phase 1 - Scaffolding] Add PackageReference entries to Directory.Packages.props for new dependencies' - done: false - - task: '[Phase 1 - Scaffolding] Create src/McpServer.Client/README.md with usage examples (included in NuGet package)' - done: false - - task: '[Phase 1 - Scaffolding] Configure GenerateDocumentationFile=true, verify dotnet build and dotnet pack succeed locally' - done: false - - task: '[Phase 2 - DTOs] Create Models/ directory with all request/response record types' - done: false - - task: '[Phase 2 - DTOs] WorkspaceModels.cs: WorkspaceDto, WorkspaceCreateRequest, WorkspaceUpdateRequest, WorkspaceListResult, WorkspaceMutationResult, WorkspaceInitResult' - done: false - - task: '[Phase 2 - DTOs] TodoModels.cs: TodoFlatItem, TodoFlatTask, TodoCreateRequest, TodoUpdateRequest, TodoQueryResult, TodoMutationResult, TodoQueryRequest' - done: false - - task: '[Phase 2 - DTOs] ToolRegistryModels.cs: ToolDto, ToolCreateRequest, ToolUpdateRequest, ToolSearchResult, ToolMutationResult, BucketDto, BucketListResult, BucketBrowseResult, BucketMutationResult, BucketSyncResult, BucketAddRequest' - done: false - - task: '[Phase 2 - DTOs] SessionLogModels.cs: UnifiedSessionLogDto, SessionLogQueryRequest, SessionLogQueryResult, ProcessingDialogItemDto' - done: false - - task: '[Phase 2 - DTOs] ContextModels.cs: ContextSearchRequest, ContextSearchResult, ContextPackRequest, ContextPack, ContextDocument' - done: false - - task: '[Phase 2 - DTOs] GitHubModels.cs: GitHubIssueItem, GitHubIssueListResult, GitHubIssueDetail, GitHubIssueDetailResult, GitHubIssueRequest, GitHubCommentRequest/Result, GitHubCreateIssueResult, GitHubMutationResult, GitHubPullItem/ListResult, GitHubLabelsResult, IssueSyncResult' - done: false - - task: '[Phase 2 - DTOs] RepoModels.cs: RepoListResult, RepoListEntry, RepoFileReadResult, RepoWriteRequest, RepoWriteResult' - done: false - - task: '[Phase 2 - DTOs] SyncModels.cs: SyncRunResult, SyncStatus' - done: false - - task: '[Phase 2 - DTOs] Create McpJsonContext.cs with [JsonSerializable] attributes for all types (AOT source generator)' - done: false - - task: '[Phase 2 - DTOs] Add XML-doc summaries on every public type and property' - done: false - - task: '[Phase 3 - Clients] Create McpServerClientOptions.cs: BaseUrl (Uri), ApiKey (string?), Timeout (TimeSpan, default 30s)' - done: false - - task: '[Phase 3 - Clients] Create base McpClientBase.cs: shared HttpClient, JSON serialization, error handling, API key header injection, typed exception mapping' - done: false - - task: '[Phase 3 - Clients] WorkspaceClient.cs: ListAsync, GetAsync, CreateAsync, UpdateAsync, DeleteAsync, InitAsync, StartAsync, StopAsync, GetStatusAsync - 9 methods' - done: false - - task: '[Phase 3 - Clients] TodoClient.cs: QueryAsync, GetAsync, CreateAsync, UpdateAsync, DeleteAsync, AnalyzeRequirementsAsync - 6 methods' - done: false - - task: '[Phase 3 - Clients] ToolRegistryClient.cs: ListAsync, SearchAsync, GetAsync, CreateAsync, UpdateAsync, DeleteAsync, ListBucketsAsync, CreateBucketAsync, DeleteBucketAsync, BrowseBucketAsync, InstallBucketAsync, SyncBucketAsync - 12 methods' - done: false - - task: '[Phase 3 - Clients] SessionLogClient.cs: SubmitAsync, QueryAsync, AppendDialogAsync - 3 methods' - done: false - - task: '[Phase 3 - Clients] ContextClient.cs: SearchAsync, RebuildIndexAsync, PackAsync, ListSourcesAsync - 4 methods' - done: false - - task: '[Phase 3 - Clients] GitHubClient.cs: ListIssuesAsync, GetIssueAsync, CreateIssueAsync, UpdateIssueAsync, CloseIssueAsync, ReopenIssueAsync, CommentOnIssueAsync, ListLabelsAsync, ListPullsAsync, CommentOnPullAsync, SyncFromGitHubAsync, SyncToGitHubAsync, SyncIssueAsync - 13 methods' - done: false - - task: '[Phase 3 - Clients] RepoClient.cs: ReadFileAsync, WriteFileAsync, ListAsync - 3 methods' - done: false - - task: '[Phase 3 - Clients] SyncClient.cs: RunAsync, GetStatusAsync - 2 methods' - done: false - - task: '[Phase 4 - Facade/DI] Create McpServerClient.cs: facade owning all 8 sub-clients as properties (Workspace, Todo, Tools, SessionLog, Context, GitHub, Repo, Sync)' - done: false - - task: '[Phase 4 - Facade/DI] Create ServiceCollectionExtensions.cs: AddMcpServerClient(Action) with named HttpClient via IHttpClientFactory' - done: false - - task: '[Phase 4 - Facade/DI] Create McpServerClientFactory.cs for non-DI scenarios' - done: false - - task: "[Phase 5 - CI Pipeline] Add 'publish-nuget' job to mcp-server-ci.yml, depends on build-test-publish, push-only (no PRs)" - done: false - - task: '[Phase 5 - CI Pipeline] Read version from .version file; set VERSION (stable for main, -preview.{run_number} for other branches)' - done: false - - task: '[Phase 5 - CI Pipeline] dotnet pack McpServer.Client -c Release -p:PackageVersion=$VERSION -o ./nupkg' - done: false - - task: '[Phase 5 - CI Pipeline] Main branch: dotnet nuget push to https://api.nuget.org/v3/index.json --api-key secrets.NUGET_API_KEY --skip-duplicate' - done: false - - task: '[Phase 5 - CI Pipeline] Non-main: dotnet nuget push to https://nuget.pkg.github.com/sharpninja/index.json --api-key secrets.GITHUB_TOKEN --skip-duplicate' - done: false - - task: '[Phase 5 - CI Pipeline] Upload .nupkg as build artifact; document NUGET_API_KEY secret requirement in README' - done: false - - task: '[Phase 6 - Testing] Create tests/McpServer.Client.Tests/ (xUnit v3, net9.0) with mocked HttpMessageHandler unit tests' - done: false - - task: '[Phase 6 - Testing] Unit tests for each sub-client: URL construction, HTTP method, headers, request serialization, response deserialization' - done: false - - task: '[Phase 6 - Testing] Test error handling: 400→McpValidationException, 404→McpNotFoundException, 401→McpUnauthorizedException, 500→McpServerException' - done: false - - task: '[Phase 6 - Testing] Integration smoke tests gated behind MCP_TEST_BASE_URL env var' - done: false - - task: '[Phase 7 - Docs/Release] Update root README.md with client library section and install instructions' - done: false - - task: '[Phase 7 - Docs/Release] Write src/McpServer.Client/README.md with installation, quick start, DI setup, all client method listing' - done: false - - task: '[Phase 7 - Docs/Release] Add CHANGELOG.md entry; tag v{version} after first nuget.org publish; verify package on nuget.org' - done: false - - id: frp-railway-tunnel - title: FRP tunnel provider hardening and Railway-hosted frps deployment assets (superseded for Railway multi-port exposure) - estimate: 2-4 days - note: FRP tunnel provider work was completed, but the Railway deployment strategy is no longer the preferred path for this environment because Railway does not support the required multi-public-port exposure model (7147-7160). Keep FRP support for non-Railway scenarios; use ngrok/cloudflare strategies for this environment. - done: true - description: - - Use the existing FRP provider (frpc) in McpServer.Support.Mcp and make it production-ready for Railway-hosted frps. - - Support a simple MVP deployment path first (HTTP mode), then add hardening and operational visibility. - - Provide Railway deployment assets and a runbook so a local MCP instance can connect to a self-hosted frps service. - technical-details: - - 'Existing integration points: src/McpServer.Support.Mcp/Services/FrpTunnelProvider.cs, src/McpServer.Support.Mcp/Options/TunnelOptions.cs, src/McpServer.Support.Mcp/Program.cs.' - - MVP should preserve backward compatibility with current Mcp:Tunnel:Frp settings (ServerAddress, ServerPort, Token, Subdomain, CustomDomain). - - 'Add Railway-focused options only as needed (for example: PublicBaseUrl, StartupTimeoutSeconds, ProxyType).' - - Prefer HTTP proxy mode first because current FrpTunnelProvider.GenerateConfig() already emits FRP HTTP config. - - Secrets (FRP token) must not be logged or written to committed files. - implementation-tasks: - - task: '[Commit 1 - MVP] Extend FrpTunnelOptions in src/McpServer.Support.Mcp/Options/TunnelOptions.cs with Railway-ready fields (PublicBaseUrl, StartupTimeoutSeconds, ProxyType defaulting to http) while keeping existing options backward compatible' - done: true - - task: '[Commit 1 - MVP] Update src/McpServer.Support.Mcp/Services/FrpTunnelProvider.cs to prefer PublicBaseUrl when building TunnelStatus.PublicUrl, then fall back to CustomDomain/Subdomain behavior' - done: true - - task: '[Commit 1 - MVP] Add startup timeout and clear error reporting in FrpTunnelProvider when frpc does not connect successfully (avoid silent hang/optimistic success)' - done: true - - task: '[Commit 1 - MVP] Add provider startup validation/logging in FrpTunnelProvider (sanitized server/port/proxy type) and optional Program.cs log indicating Provider=frp selected' - done: true - - task: '[Commit 2 - Hardening] Capture frpc stdout/stderr asynchronously in FrpTunnelProvider, surface actionable errors in TunnelStatus.Error, and log connection lifecycle without exposing secrets' - done: true - - task: '[Commit 2 - Hardening] Add FRP option validation in FrpTunnelProvider for incompatible/missing combinations (for example Subdomain + CustomDomain, unsupported ProxyType, missing required values)' - done: true - - task: '[Commit 2 - Hardening] Handle frpc process exit after startup and update provider status/error state so GetStatusAsync reports crashes accurately' - done: true - - task: '[Commit 3 - Railway Assets] Add infra/frp/railway/Dockerfile to run self-hosted frps on Railway' - done: true - - task: '[Commit 3 - Railway Assets] Add infra/frp/railway/entrypoint.sh and frps.toml.template to generate frps runtime config from environment variables (token auth + HTTP vhost mode)' - done: true - - task: '[Commit 3 - Railway Assets] Add infra/frp/railway/.env.example and README.md documenting required Railway service variables and exposed ports' - done: true - - task: '[Commit 3 - Railway Assets] Optional local parity: add infra/frp/local/docker-compose.frps.yml for local frps validation before Railway deployment' - done: true - - task: '[Commit 4 - Tests] Add tests/McpServer.Support.Mcp.Tests/Services/FrpTunnelProviderTests.cs covering config generation, PublicUrl precedence (PublicBaseUrl > CustomDomain > Subdomain), and invalid-option validation' - done: true - - task: '[Commit 4 - Tests] Add tests for missing frpc binary / startup failure paths and temp config cleanup behavior in FrpTunnelProvider' - done: true - - task: '[Commit 5 - Docs] Add docs/Operations/Tunnel-FRP-Railway.md runbook with Railway frps deployment steps, TCP proxy setup for frps bind port, and MCP appsettings.json examples for Mcp:Tunnel:Provider=frp' - done: true - - task: '[Commit 5 - Docs] Add troubleshooting notes (token mismatch, wrong public URL, port mismatch, frpc not found) and an end-to-end validation checklist (/health through FRP public URL)' - done: true - - id: ngrok-tunnel-strategy - title: ngrok tunnel strategy for MCP remote/mobile access in single-public-port environments - estimate: 1-2 days - note: ngrok provider already exists (NgrokTunnelProvider). This strategy is the preferred managed-tunnel path when the hosting/network environment does not support exposing multiple public ports. - done: true - description: - - Use the existing ngrok provider in McpServer.Support.Mcp for the primary MCP host endpoint on port 7147. - - 'Strategy decision: single-public-port ngrok deployments expose the primary MCP host only (7147). Child workspace listeners (7147+) remain private unless a separate gateway/proxy feature is implemented.' - - Add operational guidance and validation steps for local/dev and deployed environments, including OIDC proxy endpoints for mobile device-flow auth on the same public hostname. - technical-details: - - 'Existing integration points: src/McpServer.Support.Mcp/Services/NgrokTunnelProvider.cs, src/McpServer.Support.Mcp/Options/TunnelOptions.cs, src/McpServer.Support.Mcp/Program.cs.' - - Current provider starts `ngrok http {Mcp:Tunnel:Port}` and discovers the public URL via the local ngrok API (`http://127.0.0.1:4040/api/tunnels`) using `curl`. - - 'ngrok auth token handling is already secret-safe in provider startup: token is passed via `NGROK_AUTHTOKEN` environment variable instead of CLI args.' - - No generic primary-host reverse proxy exists today for child workspace ports; strategy is primary-only public exposure. Use FRP TCP mode for multi-port/child-workspace public access. - - 'Remote/mobile auth can stay on the same public ngrok hostname via existing OIDC proxy routes: `/auth/config`, `/auth/device`, `/auth/token`, and `/auth/ui/*`.' - implementation-tasks: - - task: '[Commit 1 - Strategy] Decide and document single-public-endpoint access model for workspaces when Provider=ngrok (chosen: primary-only exposure; child workspace ports remain private)' - done: true - - task: '[Commit 2 - Provider Hardening] Verify NgrokTunnelProvider startup/error/status behavior and add missing timeout/exit diagnostics (including clearer handling when ngrok local API/curl is unavailable)' - done: true - - task: '[Commit 3 - Docs] Add docs/Operations/Tunnel-Ngrok.md runbook with appsettings.json examples, token setup, single-port workspace access model, OIDC proxy notes, and public /health validation checklist' - done: true - - id: cloudflare-tunnel-strategy - title: Cloudflare Tunnel strategy for MCP remote/mobile access in single-public-port environments - estimate: 1-3 days - note: Cloudflare tunnel provider already exists (CloudflareTunnelProvider). This strategy is the preferred no-open-port path when Cloudflare DNS/Tunnel is available. - done: true - description: - - Use the existing Cloudflare tunnel provider in McpServer.Support.Mcp to expose the primary MCP host endpoint on port 7147. - - 'Strategy decision: single-host Cloudflare Tunnel deployments expose the primary MCP host only (7147). Child workspace listeners (7147+) remain private unless a separate gateway/proxy feature is implemented.' - - Produce deployment guidance for cloudflared quick tunnels and named tunnels, including credentials/runtime prerequisites and hostname routing responsibilities. - technical-details: - - 'Existing integration points: src/McpServer.Support.Mcp/Services/CloudflareTunnelProvider.cs, src/McpServer.Support.Mcp/Options/TunnelOptions.cs, src/McpServer.Support.Mcp/Program.cs.' - - Current provider supports quick tunnel mode (`cloudflared tunnel --url http://localhost:{port}`) and named tunnel mode (`cloudflared tunnel run {TunnelName}`); it captures quick-tunnel URLs by parsing stderr. - - Named tunnel hostnames/DNS routes are managed outside the provider (Cloudflare dashboard or cloudflared commands). `Hostname` is only passed in quick-tunnel mode in the current implementation. - - 'Document prerequisites: Cloudflare account/zone, cloudflared login + named tunnel creation (for stable hostnames), and credentials/config availability for the runtime account.' - - Validate public URL/status reporting and error surfacing when cloudflared is missing or tunnel auth is invalid; named tunnel status may be healthy even when no URL is captured from stderr. - - 'Remote/mobile auth can stay on the same public Cloudflare hostname via existing OIDC proxy routes: `/auth/config`, `/auth/device`, `/auth/token`, and `/auth/ui/*`.' - implementation-tasks: - - task: '[Commit 1 - Strategy] Decide and document single-host workspace access model for Provider=cloudflare (chosen: primary-only exposure; child workspace ports remain private)' - done: true - - task: '[Commit 2 - Provider Hardening] Verify CloudflareTunnelProvider startup/error/status behavior and add startup timeout/process-exit diagnostics plus improved URL/status reporting for named tunnels' - done: true - - task: '[Commit 3 - Docs] Add docs/Operations/Tunnel-Cloudflare.md runbook with quick/named tunnel setup, hostname routing, appsettings.json examples, single-port workspace access model, and public /health validation checklist' - done: true -saas: - high-priority: [] - medium-priority: [] - low-priority: - - id: saas-consolidated-roadmap - title: SaaS planning and delivery roadmap (consolidated) - estimate: 3-6 weeks - note: 'Consolidated from former SAAS todo items into a single parked backlog item per prioritization request. Archived detail: docs/Project/SaaS-TODO-Archive-2026-03-03.yaml.' - done: true - description: - - Keep SaaS work tracked as one deferred stream until it is actively scheduled. - - Cover business plan, hosted product architecture, go-to-market, client SDK distribution, and operations/compliance in one unified plan. - - Split into implementation-sized TODOs only when the SaaS stream is re-prioritized. - implementation-tasks: - - task: Build a single unified SaaS scope document and milestone map. - done: false - - task: Revalidate market, pricing, cost, and compliance assumptions before execution. - done: false - - task: Expand this item back into execution TODOs when work is resumed. - done: false -mvp-app: - high-priority: - - id: MVP-MCP-001 - title: '[READY] Add notifications about changed context (including session logs) on changes within a workspace' - estimate: '"8-12 hours AI-assisted"' - note: '"Audit 2026-03-01. Infrastructure built: ChannelChangeEventBus.cs exists, EventStreamController.cs exists at /mcpserver/events with SSE streaming. NON-FUNCTIONAL: ChannelChangeEventBus NOT registered in DI (runtime crash), ZERO PublishAsync calls in codebase, no services inject IChangeEventBus. EventStreamController references FR-MCP-031 (Web UI) - needs dedicated FR (FR-MCP-049). 52 mutation points across 12 services need event publishing wired up."' - done: true - description: - - Implement a notification/event system that alerts connected agents when workspace context changes - - Include session log updates, context source changes, file modifications, and other relevant mutations within a workspace - - 'Infrastructure audit (2026-02-27): ChangeEvent model (5 files in Notifications/), EventStreamController (GET /mcpserver/events SSE), InteractionLoggingMiddleware SSE bypass - all exist but bus is not in DI and nothing publishes events' - - '52 mutation points across 12 services/controllers need PublishAsync calls: todo(4), session_log(2), repo(1), context(2), tool_registry(4), tool_bucket(3), workspace(7), github(9), marker(2), agent(8), requirements(11)' - remaining: '"Completed: event bus wiring, workspace mutation publishing coverage, notification tests, requirements traceability updates, and SSE integration validation."' - technical-details: - - 'ARCHITECTURE: In-process fan-out pub/sub via ChannelChangeEventBus (bounded channel, 1000-item buffer, drop-oldest). SSE delivery via EventStreamController at GET /mcpserver/events?category=xxx. Per-subscriber channels ensure independent consumption.' - - 'DI REGISTRATION: builder.Services.AddSingleton() in Program.cs - MUST be singleton so all scoped services and the SSE controller share the same bus instance.' - - 'PUBLISH LOCATION: Service layer (not controllers) for all CRUD operations so internal callers (IssueTodoSyncService, RequirementsService.AnalyzeAsync) also emit events. Controller-only for operations that bypass services (GitHubController gh cli calls, workspace start/stop side effects).' - - 'UPSERT DETECTION: For upsert methods (SessionLogService.SubmitAsync, AgentService.UpsertDefinitionAsync/UpsertWorkspaceAgentAsync), detect create vs update by checking if entity existed before write, then emit appropriate ChangeEventActions.Created or .Updated.' - - "NEW CATEGORIES: Add 'agent' and 'requirements' to ChangeEventCategories.cs. These are needed for AgentService (8 mutations) and RequirementsDocumentService (11 mutations)." - - 'CONSTRUCTOR INJECTION PATTERN: Add IChangeEventBus parameter to service constructors. For TodoService which has 2 constructors (DI + internal test), add to both. For services using primary constructors (like RequirementsService), add parameter to the primary constructor.' - - 'FR-MCP-031 FIX: EventStreamController.cs line 8 incorrectly references FR-MCP-031 (McpServer Management Web UI). Change to FR-MCP-045 (new Workspace Change Notifications FR).' - - 'FIRE-AND-FORGET: PublishAsync is synchronous (writes to all subscriber channels via TryWrite), so no need for try/catch or background queueing. However, wrap in try/catch with LogWarning for defensive coding per TR-MCP-LOG-001.' - - 'RESOURCE URI CONVENTION: mcp://workspace/{category}/{entityId} - e.g. mcp://workspace/todo/MVP-MCP-001, mcp://workspace/sessionlog/Copilot/session-123, mcp://workspace/gh/issues/42.' - - 'TEST STRATEGY: (1) ChannelChangeEventBusTests - publish/subscribe fan-out, buffer overflow drop-oldest, cancellation, multiple subscribers. (2) Per-service tests verifying PublishAsync is called with correct category/action/entityId after each mutation - use NSubstitute mock of IChangeEventBus. (3) EventStreamController integration test via CustomWebApplicationFactory - register bus, publish event, verify SSE output.' - functional-requirements: - - FR-MCP-062 - technical-requirements: - - TR-MCP-EVT-001 - - TR-MCP-EVT-002 - - TR-MCP-EVT-003 - - TR-MCP-EVT-004 - - TR-MCP-EVT-005 - implementation-tasks: - - task: Phase 0 - Audit and document current state (ChangeEvent model, ChannelChangeEventBus, EventStreamController, InteractionLoggingMiddleware SSE bypass, SessionLogFileWatcher). Verify all 5 Notifications/ files compile. Verify EventStreamController would crash without DI registration. - done: true - - task: "Phase 1.1 - Register ChannelChangeEventBus in DI: Add \builder.Services.AddSingleton(); to Program.cs in the service registration block (after line ~269, near other singletons). Verify /mcpserver/events endpoint no longer crashes (returns empty SSE stream)." - done: true - - task: "Phase 1.2 - Add new ChangeEventCategories: Add public const string Agent = \agent; and public const string Requirements =" - done: true - - task: 'Phase 1.3 - Fix FR reference: Change EventStreamController.cs line 8 from FR-MCP-031 to FR-MCP-045.' - done: true - - task: 'Phase 2.1 - TodoService: Add IChangeEventBus parameter to BOTH constructors (public DI constructor line 36 AND internal test constructor line 48). Store as private readonly IChangeEventBus _eventBus;. In CreateAsync after successful YAML write + audit log, call _eventBus.PublishAsync(new ChangeEvent { Category = ChangeEventCategories.Todo, Action = ChangeEventActions.Created, EntityId = item.Id, ResourceUri = $mcp://workspace/todo/{item.Id} }). Similarly for UpdateAsync (Action=Updated) and DeleteAsync (Action=Deleted). Wrap each PublishAsync in try/catch with _logger.LogWarning.' - done: true - - task: 'Phase 2.2 - SqliteTodoService: Add IChangeEventBus parameter to constructor (line 21). Store as field. Add PublishAsync calls in CreateAsync (after INSERT + audit), UpdateAsync (after UPDATE + audit), DeleteAsync (after DELETE + audit) with same pattern as TodoService. Wrap in try/catch.' - done: true - - task: 'Phase 2.3 - TodoService DI factory update: In Program.cs line ~226 (AddSingleton factory delegate), pass sp.GetRequiredService() to both TodoService and SqliteTodoService constructors via ActivatorUtilities.CreateInstance.' - done: true - - task: "Phase 2.4 - SessionLogService: Add IChangeEventBus parameter to constructor (line 23). Store as field. In SubmitAsync, detect create vs update (check if \existing == null before upsert), then PublishAsync with Category=SessionLog, Action=Created or Updated, EntityId={dto.SourceType}/{dto.SessionId}. In AppendProcessingDialogAsync, PublishAsync with Action=Updated. Wrap in try/catch." - done: true - - task: 'Phase 2.5 - RepoFileService: Add IChangeEventBus parameter to constructor. In WriteAsync, check File.Exists before write to detect create vs update. After successful write, PublishAsync with Category=Repo, Action=Created or Updated, EntityId=relativePath. Wrap in try/catch.' - done: true - - task: 'Phase 2.6 - ToolRegistryService: Add IChangeEventBus parameter to constructor (line 19). In CreateAsync after db.SaveChangesAsync, PublishAsync Category=ToolRegistry, Action=Created, EntityId=entity.Id.ToString(). In UpdateAsync after save, Action=Updated. In DeleteAsync after save, Action=Deleted. Wrap in try/catch.' - done: true - - task: 'Phase 2.7 - ToolBucketService: Add IChangeEventBus parameter to constructor. In AddBucketAsync after save, PublishAsync Category=ToolBucket, Action=Created, EntityId=name. In RemoveBucketAsync after save, Action=Deleted (also emit ToolRegistry/Deleted for each tool if uninstallTools=true). In SyncAsync after completion, Action=Updated. Wrap in try/catch.' - done: true - - task: 'Phase 3.1 - WorkspaceService: Add IChangeEventBus parameter to constructor. In CreateAsync after appsettings write, PublishAsync Category=Workspace, Action=Created, EntityId=workspace path. In UpdateAsync after save, Action=Updated. In DeleteAsync after removal, Action=Deleted. In InitAsync after init, Action=Updated. Wrap in try/catch.' - done: true - - task: 'Phase 3.2 - WorkspaceController start/stop: Inject IChangeEventBus via [FromServices]. In StartAsync after successful start, PublishAsync Category=Workspace, Action=Updated, EntityId=workspace path. Same for StopAsync. In UpdateGlobalPromptAsync after write, PublishAsync Category=Workspace, Action=Updated, EntityId=global-prompt. Wrap in try/catch.' - done: true - - task: 'Phase 3.3 - AgentService: Add IChangeEventBus parameter to constructor. In UpsertDefinitionAsync, detect create vs update, PublishAsync Category=Agent, Action=Created/Updated, EntityId=agentType. In DeleteDefinitionAsync, Action=Deleted. In SeedDefaultsAsync, Action=Created for each seed. In UpsertWorkspaceAgentAsync, detect create/update, EntityId=agentId. In DeleteWorkspaceAgentAsync, Action=Deleted. In BanAgentAsync/UnbanAgentAsync, Action=Updated. In LogEventAsync, Action=Created. Total: 8 PublishAsync calls. Wrap each in try/catch.' - done: true - - task: 'Phase 3.4 - RequirementsDocumentService: Add IChangeEventBus parameter to primary constructor. In CreateFrAsync/UpdateFrAsync/DeleteFrAsync, PublishAsync Category=Requirements, EntityId=frId. Same pattern for TR (CreateTrAsync/UpdateTrAsync/DeleteTrAsync), TEST (CreateTestAsync/UpdateTestAsync/DeleteTestAsync), and Mapping (UpsertMappingAsync/DeleteMappingAsync). Total: 11 PublishAsync calls. Wrap each in try/catch.' - done: true - - task: 'Phase 3.5 - IngestionCoordinator: Add IChangeEventBus parameter to constructor. In RunAsync after successful sync completion, PublishAsync Category=Context, Action=Updated, EntityId=null, ResourceUri=mcp://workspace/context/sync. Wrap in try/catch.' - done: true - - task: 'Phase 4.1 - GitHubController: Inject IChangeEventBus via [FromServices] on each mutating action method. In CreateIssueAsync after successful gh cli call, PublishAsync Category=GitHub, Action=Created, EntityId=issue number. In UpdateIssueAsync/CloseIssueAsync/ReopenIssueAsync, Action=Updated. In CommentOnIssueAsync/CommentOnPullAsync, Action=Updated. In sync endpoints (SyncFromGitHubAsync/SyncToGitHubAsync/SyncSingleIssueAsync), Action=Updated. Total: 9 PublishAsync calls. Wrap each in try/catch.' - done: true - - task: 'Phase 4.2 - MarkerFileService callers: MarkerFileService is static, so publish from WorkspaceProcessManager or wherever marker writes/deletes are triggered. PublishAsync Category=Marker, Action=Created/Updated on write, Action=Deleted on removal. Identify all call sites in WorkspaceProcessManager and MarkerFileService.WriteAsync/RemoveAsync callers. Wrap in try/catch.' - done: true - - task: 'Phase 5.1 - ChannelChangeEventBusTests (unit test): Create tests/McpServer.Support.Mcp.Tests/Services/ChannelChangeEventBusTests.cs. Test cases: (1) PublishAsync_NoSubscribers_DoesNotThrow, (2) PublishAsync_SingleSubscriber_ReceivesEvent, (3) PublishAsync_MultipleSubscribers_AllReceiveEvent (fan-out), (4) SubscribeAsync_CancellationToken_StopsEnumeration, (5) PublishAsync_BufferFull_DropsOldest (publish 1001+ events to verify), (6) SubscribeAsync_SubscriberRemoved_AfterCancellation. Pattern: sealed class, _sut = new ChannelChangeEventBus(), Assert.*.' - done: true - - task: 'Phase 5.2 - TodoService event publishing tests: In existing TodoServiceTests.cs (or new file), add tests: (1) CreateAsync_Success_PublishesCreatedEvent, (2) UpdateAsync_Success_PublishesUpdatedEvent, (3) DeleteAsync_Success_PublishesDeletedEvent, (4) CreateAsync_Failure_DoesNotPublish. Mock IChangeEventBus with NSubstitute, verify Received().PublishAsync(Arg.Is(e => e.Category == odo && e.Action == created)).' - done: true - - task: 'Phase 5.3 - SessionLogService event publishing tests: Add tests to SessionLogServiceTests or new file: (1) SubmitAsync_NewSession_PublishesCreatedEvent, (2) SubmitAsync_ExistingSession_PublishesUpdatedEvent, (3) AppendDialogAsync_Success_PublishesUpdatedEvent. Mock IChangeEventBus, verify category=session_log.' - done: true - - task: 'Phase 5.4 - EventStreamController integration test: Create tests/McpServer.Support.Mcp.Tests/Controllers/EventStreamIntegrationTests.cs. Use CustomWebApplicationFactory with IChangeEventBus registered. Test: (1) GET /mcpserver/events returns text/event-stream content type, (2) publishing an event to the bus produces SSE output with correct event: and data: lines, (3) category filter works. Use HttpClient with SendAsync + HttpCompletionOption.ResponseHeadersRead for streaming.' - done: true - - task: 'Phase 5.5 - Extended service event publishing tests: Add at least one PublishAsync verification test for each of: ToolRegistryService (create publishes tool_registry/created), WorkspaceService (create publishes workspace/created), AgentService (upsert new publishes agent/created, upsert existing publishes agent/updated), RepoFileService (write new file publishes repo/created). NSubstitute mock pattern.' - done: true - - task: Phase 6.1 - Create FR-MCP-062 in Functional-Requirements.md for workspace change notifications with SSE delivery at GET /mcpserver/events. - done: true - - task: Phase 6.2 - Create TR-MCP-EVT-001..005 in Technical-Requirements.md covering bus architecture, service-layer publishing, SSE delivery, event contract, and category coverage. - done: true - - task: Phase 6.3 - Create TEST-MCP-075..080 in Testing-Requirements.md for bus behavior, service publish verification, extended service verification, SSE integration, and category filtering. - done: true - - task: 'Phase 6.4 - Update TR-per-FR-Mapping.md: Add row FR-MCP-062 → TR-MCP-EVT-001..005.' - done: true - - task: Phase 6.5 - Update Requirements-Matrix.md with FR-MCP-062, TR-MCP-EVT-001..005, and TEST-MCP-075..080 statuses. - done: true - - task: 'Phase 7 - Build verification: dotnet build src\McpServer.Support.Mcp -c Debug must pass with zero warnings (TreatWarningsAsErrors). All new public types must have XML doc comments (CS1591). Verify no missing ConfigureAwait(false) on async calls.' - done: true - - task: 'Phase 8 - Test execution: dotnet test tests\McpServer.Support.Mcp.Tests -c Debug must pass all existing tests plus all new notification tests. Zero regressions. Run with --filter to verify each new test class independently.' - done: true - - task: Phase 9 - SSE smoke validation covered by EventStreamIntegrationTests (stream content-type, todo category filter, and emitted event payload assertions). - done: true - - id: MT-001 - title: Eliminate Multi-Instance Architecture - Single-Port Multi-Tenant - note: 'Phase 1-3,5-7 DONE. 32/44 todos complete. 7 commits on develop. 58 multi-tenant tests + 84 client tests pass. Remaining: Phase 2 EF migration, Phase 4 remove multi-instance (WorkspaceAppFactory, ProcessManager), integration tests, stdio-contract.' - done: true - description: - - Consolidate from N separate WebApplication instances into single-port multi-tenant model. - - 'Resolution: X-Workspace-Path header > API key reverse lookup > default workspace.' - - Shared SQLite DB with WorkspaceId discriminator. - - '7 phases: Resolution Layer, DB Consolidation, Service Multi-Tenancy, Remove Multi-Instance, Director Updates, Testing, Documentation.' - - id: sessionlog-commit-collection - title: Create collection for commits on the request object in the session log - note: 'All 13 code implementation tasks verified complete in codebase. Build passes with 0 warnings, all 515 tests pass (434 + 81). Remaining: E2E deploy verification and final TODO/docs update. Migration was combined into single file 20260301111848_AddSessionLogCommitsAndStringLists.cs (not split as originally planned).' - done: true - description: - - Add a commits collection property to the session log RequestEntry object - - Allow agents to log git commits (SHA, branch, message, files changed) as structured data alongside each request entry - technical-details: - - 10 tasks across 2 new files and 5 modified files - - 'SessionLogCommitDto: Sha, Branch, Message, Author, Timestamp, FilesChanged (List)' - - 'SessionLogCommitEntity: 4NF child of SessionLogEntryEntity, FK + cascade delete' - - FilesChanged stored as JSON string (FilesChangedJson) to avoid 4th-level entity - - CommitTimestamp (not Timestamp) to avoid name collision with base properties - - 'Migration: 20260302000000_AddSessionLogCommits (CreateTable + FK + indexes on SessionLogEntryId and WorkspaceId)' - - 'Service: MapCommits, DeserializeStringList, UpdateEntryFromDto, MapSingleEntry, MapEntityToDto, Include chains' - - 'Client mirror: SessionLogCommitDto + Commits property in McpServer.Client/Models/SessionLogModels.cs' - - 'No new endpoints: commits flow through existing POST /mcpserver/sessionlog' - - 'No CQRS/Director changes: commits are submitted not queried independently' - implementation-tasks: - - task: 'commit-dto: Add SessionLogCommitDto class + Commits property to UnifiedSessionLogDto.cs' - done: false - - task: 'commit-entity: Create SessionLogCommitEntity.cs (4NF child entity with FK to SessionLogEntryEntity)' - done: false - - task: 'commit-entry-nav: Add ICollection Commits navigation to SessionLogEntryEntity.cs' - done: false - - task: 'commit-dbcontext: Register in McpDbContext (DbSet, Fluent API HasOne/WithMany/FK/Cascade, HasQueryFilter)' - done: false - - task: 'commit-migration: Hand-written migration 20260302000000_AddSessionLogCommits.cs (CreateTable + FK + indexes)' - done: false - - task: 'commit-service-mapping: Add MapCommits, DeserializeStringList, update UpdateEntryFromDto/MapSingleEntry/MapEntityToDto/Include chains' - done: false - - task: 'commit-client-dto: Mirror SessionLogCommitDto + Commits property in McpServer.Client/Models/SessionLogModels.cs' - done: false - - task: 'stringlist-entity: Create SessionLogEntryStringListEntity.cs (4NF generic with ListType discriminator)' - done: false - - task: 'stringlist-entry-nav: Add ICollection StringListItems to SessionLogEntryEntity' - done: false - - task: 'stringlist-dbcontext: Register in McpDbContext (DbSet, Fluent API, composite index on EntryId+ListType, HasQueryFilter)' - done: false - - task: 'stringlist-migration: Migration 20260302000001_AddSessionLogEntryStringLists.cs' - done: false - - task: 'stringlist-service-mapping: MapStringListItems/AddStringListItems/MapStringListToDto + UpdateEntryFromDto/MapSingleEntry/MapEntityToDto/Include chains' - done: false - - task: 'stringlist-client-dto: Add DesignDecisions/RequirementsDiscovered/FilesModified/Blockers to client DTO if missing' - done: false - - task: 'commit-build-verify: Build + test all projects (0 warnings, all tests pass)' - done: false - - task: 'commit-deploy-verify: Deploy server, E2E test commits + string-lists round-trip' - done: false - - task: 'commit-todo-update: Mark done, update FR/TR docs, update session log' - done: false - - id: MCP-NAMING-CONVENTIONS-001 - title: '[DONE] Add naming conventions for TODO and Sessions to marker/context files' - note: 'Implemented via PLAN-NAMINGCONVENTIONS-001: marker/template naming guidance, normative context docs, TODO + session/request ID validators, controller/service enforcement, expanded regression tests, and FR/TR/TEST traceability updates.' - done: true - description: - - Document standard naming conventions for TODO item IDs (e.g. prefix patterns, kebab-case rules, section scoping) and session log IDs (sessionId, requestId formats) in the marker file prompt and/or docs/context/ reference files so all agents follow consistent naming. - - 'KEBAB-CASE: Yes, upper case only' - - '3 Segments: --###' - - Add to marker template. - depends-on: - - PLAN-NAMINGCONVENTIONS-001 - - id: MCP-GRAPHRAG-001 - title: '[DONE] Integrate GraphRAG (productionized)' - estimate: 5-7 days - note: AUDITED on 2026-03-04. Existing GraphRAG implementation is partially complete (framework + integration points present) and now has a detailed execution plan with explicit completed-vs-remaining tasks. - done: true - completed: 2026-03-04T23:07:31.9611593Z - description: - - 'Audit result: GraphRAG scaffolding is already implemented across server, MCP tools, and client SDK, but runtime behavior is currently an internal fallback adapter rather than full graph construction/query execution.' - - 'Implemented today (verified in code): GraphRag options + DI registration, GraphRag service contract/implementation, GraphRag REST controller, MCP tools (graphrag_status/index/query), context-search integration hook, client methods/models, and baseline tests.' - - 'Primary gaps: indexing does not build a real graph, query modes (local/global/drift) are not semantically differentiated, backend command options are not executed, no per-workspace index job locking, and limited observability/contracts around readiness/errors/citations quality.' - - 'Goal for this TODO: evolve from fallback simulation to production-grade GraphRAG pipeline with deterministic workspace isolation, robust indexing lifecycle, explicit query-mode behavior, and strong tests + operational tooling.' - done-summary: Completed GraphRAG productionization with backend adapter abstraction, stale artifact cleanup, OpenAPI metadata expansion, dedicated MCP transport GraphRAG tool tests, and validated builds/tests for server and client. - remaining: '' - technical-details: - - 'Code audited for current state: src/McpServer.Support.Mcp/Options/GraphRagOptions.cs, src/McpServer.Support.Mcp/Services/IGraphRagService.cs, src/McpServer.Support.Mcp/Services/GraphRagService.cs, src/McpServer.Support.Mcp/Controllers/GraphRagController.cs, src/McpServer.Support.Mcp/Controllers/ContextController.cs, src/McpServer.Support.Mcp/McpStdio/McpServerMcpTools.cs.' - - 'Client and tests audited: src/McpServer.Client/ContextClient.cs, src/McpServer.Client/Models/ContextModels.cs, tests/McpServer.Support.Mcp.Tests/Controllers/GraphRagControllerTests.cs, tests/McpServer.Client.Tests/ContextClientTests.cs.' - - 'Current GraphRagService behavior: IndexAsync marks status as indexed without constructing graph artifacts; QueryAsync always calls IContextSearchService and synthesizes answer/citations; backend command fields are present in options but not executed.' - - 'Config defaults currently disable GraphRAG by default and enable context-search enhancement when GraphRAG is enabled: src/McpServer.Support.Mcp/appsettings.json and src/McpServer.Support.Mcp/appsettings.yaml.' - - 'Key architectural constraint: all GraphRAG filesystem state must remain workspace-local and never leak across workspace boundaries, including status files, intermediate artifacts, caches, and index outputs.' - - 'Reference planning document: docs/Project/MCP-GRAPHRAG-001-Implementation-Plan.md (needs to stay synchronized with this TODO as execution proceeds).' - implementation-tasks: - - task: Phase 0 / Audit / Task 01 - Confirm GraphRAG option binding and DI registration in Program + McpStdioHost; verify no missing service registrations for IGraphRagService across HTTP and STDIO hosts. - done: true - - task: Phase 0 / Audit / Task 02 - Confirm GraphRAG endpoint surface (status/index/query) and validate request/response DTO alignment between server and client models. - done: true - - task: Phase 0 / Audit / Task 03 - Confirm MCP tool exposure for graphrag_status/graphrag_index/graphrag_query with workspace override path handling. - done: true - - task: Phase 0 / Audit / Task 04 - Confirm context search integration hook in ContextController and document fallback path behavior. - done: true - - task: Phase 0 / Audit / Task 05 - Capture implementation gap list (real indexing, query mode semantics, external backend execution, locking, telemetry depth). - done: true - - task: 'Phase 1 / Contracts / Task 06 - Define explicit GraphRAG backend contract in service layer: initialize, index, query, status, cancellation, timeout, and error taxonomy.' - done: true - - task: Phase 1 / Contracts / Task 07 - Introduce internal backend abstraction (e.g., IGraphRagBackendAdapter) to separate orchestration concerns from backend-specific execution. - done: true - - task: Phase 1 / Contracts / Task 08 - Extend status model with richer lifecycle fields (state enum, activeJobId, lastSuccessAt, lastFailureAt, failureCode, failureMessage, artifactVersion). - done: true - - task: Phase 1 / Contracts / Task 09 - Normalize query contract to include mode-specific controls (communityDepth, maxEntities, maxRelationships, responseTokenBudget). - done: true - - task: Phase 1 / Contracts / Task 10 - Add server-side validation rules for query/index payloads with deterministic HTTP 400 responses and stable error codes. - done: true - - task: Phase 2 / Workspace Filesystem / Task 11 - Implement deterministic workspace-local GraphRAG root resolver with guardrails against cross-workspace absolute path collisions. - done: true - - task: Phase 2 / Workspace Filesystem / Task 12 - Bootstrap required folder tree (input/output/cache/logs/config) and generate default settings template when missing. - done: true - - task: Phase 2 / Workspace Filesystem / Task 13 - Implement atomic status persistence (temp-file + replace) to avoid torn writes under concurrent status reads. - done: true - - task: Phase 2 / Workspace Filesystem / Task 14 - Add integrity check routine validating critical artifact presence/version before reporting IsIndexed=true. - done: true - - task: Phase 2 / Workspace Filesystem / Task 15 - Add cleanup policy for obsolete temporary artifacts and stale partial-index remnants. - done: true - - task: Phase 3 / Index Orchestration / Task 16 - Implement real index pipeline orchestration (prepare corpus input, invoke backend build, validate outputs, update status lifecycle). - done: true - - task: Phase 3 / Index Orchestration / Task 17 - Add per-workspace index mutex/lease to enforce single active index job; return clear conflict response for concurrent starts. - done: true - - task: Phase 3 / Index Orchestration / Task 18 - Implement force reindex semantics (clear selected artifacts safely, preserve immutable config, rebuild cleanly). - done: true - - task: Phase 3 / Index Orchestration / Task 19 - Implement index timeout and cancellation propagation through backend invocation stack. - done: true - - task: Phase 3 / Index Orchestration / Task 20 - Persist rich index execution diagnostics (duration, input counts, warnings, error stage, backend invocation metadata). - done: true - - task: Phase 4 / Query Execution / Task 21 - Implement mode-aware query execution paths (local/global/drift/basic) with explicit backend selection and runtime branching. - done: true - - task: 'Phase 4 / Query Execution / Task 22 - Map backend query outputs to normalized response shape: answer, citations, chunks, sourceKeys, entities, relationships, communities.' - done: true - - task: Phase 4 / Query Execution / Task 23 - Improve citation stitching to ensure every answer claim has traceable provenance and stable source identifiers. - done: true - - task: Phase 4 / Query Execution / Task 24 - Implement degraded-mode fallback policy matrix (disabled, not indexed, backend timeout, backend error) with reason codes. - done: true - - task: Phase 4 / Query Execution / Task 25 - Add query timeout controls and cancellation behavior per mode with deterministic fallback outcomes. - done: true - - task: Phase 5 / External Backend / Task 26 - Implement safe external command execution using configured BackendCommand/BackendArgs with strict argument templating and escaping. - done: true - - task: Phase 5 / External Backend / Task 27 - Capture backend stdout/stderr, parse structured outputs where available, and persist diagnostics for supportability. - done: true - - task: Phase 5 / External Backend / Task 28 - Add backend capability probing on startup/status call to report runtime readiness before index/query attempts. - done: true - - task: Phase 5 / External Backend / Task 29 - Introduce backend selection strategy (internal-fallback vs external-command) with explicit decision logging. - done: true - - task: Phase 5 / External Backend / Task 30 - Add secure handling guidance for backend secrets/config (do not persist secrets to status files or logs). - done: true - - task: Phase 6 / API and MCP Tooling / Task 31 - Expand GraphRagController payload contracts and OpenAPI metadata for new status/query fields and error codes. - done: true - - task: Phase 6 / API and MCP Tooling / Task 32 - Extend MCP graphrag tools to expose advanced query parameters while preserving backwards-compatible defaults. - done: true - - task: Phase 6 / API and MCP Tooling / Task 33 - Ensure all GraphRAG tool responses include explicit backend/fallback metadata for agent decision-making. - done: true - - task: Phase 6 / API and MCP Tooling / Task 34 - Add guardrail in tools to prevent expensive index calls when status indicates active indexing unless force override is explicit. - done: true - - task: Phase 6 / API and MCP Tooling / Task 35 - Add typed client model updates and ContextClient methods for any new GraphRAG fields/options. - done: true - - task: Phase 7 / Context Integration / Task 36 - Refine ContextController graph integration to preserve sourceType semantics and include deterministic graphRag metadata envelope. - done: true - - task: Phase 7 / Context Integration / Task 37 - Ensure context search response compatibility for existing consumers while augmenting with graph details only when enabled. - done: true - - task: Phase 7 / Context Integration / Task 38 - Add feature toggle matrix tests for Enabled/EnhanceContextSearch combinations and verify no regressions in baseline search. - done: true - - task: Phase 8 / Testing / Task 39 - Add GraphRagService unit tests for path resolution, directory bootstrap, status persistence, lock behavior, timeout/cancel paths, and fallback matrix. - done: true - - task: Phase 8 / Testing / Task 40 - Expand GraphRagController integration tests to cover happy-path query, invalid payloads, backend failures, and conflict responses. - done: true - - task: Phase 8 / Testing / Task 41 - Expand MCP tool tests for graphrag_status/index/query including workspace override correctness and schema validation. - done: true - - task: Phase 8 / Testing / Task 42 - Expand client tests for new GraphRAG fields/options and serialization compatibility. - done: true - - task: Phase 8 / Testing / Task 43 - Add multi-workspace isolation tests proving graph artifacts/status remain isolated across workspace boundaries. - done: true - - task: Phase 9 / Operations / Task 44 - Add scripts for GraphRAG bootstrap/index smoke validation in scripts/ with workspace parameterization and CI-friendly exit codes. - done: true - - task: Phase 9 / Operations / Task 45 - Document GraphRAG enablement, indexing lifecycle, query modes, troubleshooting, and rollout guidance in README/docs. - done: true - - task: Phase 9 / Operations / Task 46 - Add observability dashboards/queries guidance (index duration, query latency, fallback rate, failure reasons). - done: true - - task: Phase 9 / Operations / Task 47 - Define release checklist and staged rollout plan (disabled by default, pilot workspace, measured enablement). - done: true - - task: Phase 10 / Exit Criteria / Task 48 - Run full build + targeted tests, capture evidence in doneSummary, and only then mark MCP-GRAPHRAG-001 complete. - done: true - - id: MCP-AGENTPOOL-SEED-001 - title: '[DONE] Seed Agent Pool per workspace/definition and enforce workspace-correct session routing' - note: Completion audit + remediation executed on 2026-03-04. Existing 7-phase implementation was largely complete; final closure addressed remaining isolation gaps (voice reuse scope, pooled device-id collisions, controller payload workspace override) and added targeted coverage for startup seeding and workspace-forced routing. - done: true - description: - - On startup, the Agent Pool should automatically seed a running agent instance for every (workspace × agent definition) combination. When an SSE or MCP session connects, route it to the agent instance that is bound to the correct workspace, ensuring workspace isolation. This prevents agents from operating against the wrong workspace context and eliminates the need for manual agent provisioning. - remaining: None. - technical-details: - - 'Audit baseline: verified existing composite runtime key in AgentPoolService (`AgentInstanceKey(agentName, workspacePath)`), startup host registration for AgentPoolSeedService in Program.cs, workspace-aware queue dispatch, and workspace-aware DTOs/controller wiring.' - - 'Gap A (voice isolation): VoiceConversationService.CreateSessionAsync reused idle sessions by agent name only; this allowed cross-workspace reuse for same agent definition.' - - 'Gap B (device identity collision): AgentPoolService.StartAgentAsync generated device IDs from workspace folder name only (`Path.GetFileName(workspace)`), allowing collisions across distinct workspaces with identical folder names.' - - 'Gap C (request override): AgentPoolController accepted caller-provided workspacePath in one-shot enqueue/resolve payloads, enabling workspace override instead of strict context-bound routing.' - - 'Remediation A: VoiceConversationService now reuses pooled sessions only when both agent name and workspace path match (case-insensitive), preserving same-workspace reuse while preventing cross-workspace bleed-through.' - - 'Remediation B: AgentPoolService now builds pooled device IDs using a deterministic SHA-256 hash of normalized workspace path (`agent-pool-{agent}@{workspaceHash}`), eliminating cross-workspace device collisions.' - - 'Remediation C: AgentPoolController now enforces workspace from WorkspaceContext for queue/resolve operations and agent runtime listing (ignores query/payload workspace overrides).' - - Validation scope includes unit coverage additions for startup seed behavior and controller workspace enforcement, plus updated voice-session reuse tests to prove workspace isolation semantics. - implementation-tasks: - - task: Phase 1 Audit - Verify startup seeding, composite keying, workspace routing, API surface, and existing tests against MCP-AGENTPOOL-SEED-001 acceptance criteria. - done: true - - task: Phase 1.1 Audit Evidence - Confirm AgentPoolSeedService is registered as hosted service and executes workspace×definition seeding flow. - done: true - - task: Phase 1.2 Audit Evidence - Confirm AgentPoolService runtime instances are keyed by (agentName, workspacePath) and dispatch resolves by workspace. - done: true - - task: Phase 1.3 Audit Gap Analysis - Identify remaining isolation risks not fully covered by current implementation/tests. - done: true - - task: Phase 2 Remediation - Fix voice-session reuse isolation so idle pooled sessions cannot be reused across workspaces. - done: true - - task: Phase 2.1 - Update VoiceConversationService.CreateSessionAsync matching predicate to include workspacePath in reuse criteria. - done: true - - task: Phase 3 Remediation - Eliminate pooled device-id collisions across workspaces with same folder name. - done: true - - task: Phase 3.1 - Introduce deterministic workspace-hash device-id builder in AgentPoolService and use it for pooled voice session creation. - done: true - - task: Phase 4 Remediation - Enforce workspace-bound request routing in AgentPoolController. - done: true - - task: Phase 4.1 - Force one-shot enqueue/resolve requests to active WorkspaceContext.WorkspacePath regardless of payload override. - done: true - - task: Phase 4.2 - Force runtime agent listing to active workspace context (ignore workspace query override). - done: true - - task: Phase 5 Tests - Expand unit tests for newly enforced workspace isolation semantics. - done: true - - task: 'Phase 5.1 - Update VoiceConversationServiceTests: same agent+workspace reuses session; same agent+different workspace creates separate sessions.' - done: true - - task: Phase 5.2 - Add AgentPoolSeedServiceTests validating only enabled workspaces are seeded and disabled pool short-circuits seeding. - done: true - - task: Phase 5.3 - Add AgentPoolControllerTests validating enqueue payload workspace override is ignored and context workspace is enforced. - done: true - - task: Phase 5.4 - Add AgentPoolControllerTests validating runtime-list endpoint uses context workspace even when query provides another workspace. - done: true - - task: Phase 6 Verification - Run builds/tests and resolve regressions introduced by MCP-AGENTPOOL-SEED-001 closure remediations. - done: true - - id: web-ui-oidc-integration - title: Web UI OIDC integration - full login/logout flow, AuthorizeRouteView, RoleContext, token forwarding, and tests - estimate: 3-4 days AI-assisted - note: 'AUDIT (2026-03-05): McpServer.Web has the OIDC middleware wired in Program.cs (AddAuthentication/AddCookie/AddOpenIdConnect, UseAuthentication/UseAuthorization, AddCascadingAuthenticationState), a correct appsettings.json Authentication section, the AuthConfig read-only display page (Phase 3.1/Phase 5), and service registrations. However the following are MISSING and must be built: (1) Login/Logout/AccessDenied pages (app cannot authenticate at all without these -- requests to /login/logout 404), (2) Routes.razor AuthorizeRouteView upgrade (Authorize attributes are currently ignored), (3) User identity header in MainLayout/NavMenu, (4) WebRoleContext connecting ClaimsPrincipal roles to IAuthorizationPolicyService, (5) WebMcpContext access-token forwarding to the McpServer API, (6) McpServer section in appsettings.json, (7) McpServer.Web.Tests tests. FR-MCP-031 is the primary requirement.' - done: true - description: - - 'Web UI needs a complete OIDC authentication integration: login challenge, logout, access-denied, AuthorizeRouteView, user identity display in nav, WebRoleContext wired to ClaimsPrincipal, bearer token forwarding from the Blazor session to the McpServer API, and end-to-end tests.' - - 'AUDIT STATUS (2026-03-05): OIDC middleware is registered in Program.cs and appsettings.json has all required config fields with placeholder values. The following are MISSING and block auth from working: Login page, Logout endpoint, AccessDenied page, AuthorizeRouteView in Routes.razor, user identity display, WebRoleContext, bearer token forwarding, McpServer config section, and Web.Tests content.' - - The McpServer.Web project already has AuthConfig display (read-only), Primer CSS layout, all feature pages (Todos/Sessions/Templates/Context/Health/Agents/Workspaces), SSE subscription, and adapter infrastructure. This TODO covers only the remaining auth wiring. - technical-details: - - 'DONE - Program.cs: AddAuthentication().AddCookie().AddOpenIdConnect() fully config-driven from Authentication:Schemes section. UseAuthentication() and UseAuthorization() in pipeline. AddCascadingAuthenticationState() registered. Authorization policies (AgentManager/Admin) driven from Authentication:Authorization:Policies.' - - 'DONE - appsettings.json: full Authentication section with Cookie (CookieName/LoginPath/LogoutPath/AccessDeniedPath), OpenIdConnect (Authority/ClientId/ClientSecret/ResponseType/CallbackPath/SignedOutCallbackPath/MapInboundClaims/GetClaimsFromUserInfoEndpoint/ClaimMapping/Scope), Authorization (RequireAuthenticatedUserByDefault:false, Policies).' - - 'DONE - Pages/Auth/AuthConfig.razor: read-only display of server OIDC config via AuthConfigViewModel. NavMenu links to /auth/config.' - - 'DONE - _Imports.razor: imports Microsoft.AspNetCore.Components.Authorization and Microsoft.AspNetCore.Authorization. CascadingAuthenticationState is registered and cascades to all components.' - - 'DONE - WebServiceRegistration.cs: IAuthConfigApiClient scoped. AddUiCore() fallback registers AllowAllRoleContext and AllowAllAuthorizationPolicyService.' - - 'MISSING - Login flow: CookieAuthenticationDefaults.LoginPath=/login but no page exists. Must be a non-interactive Razor Page (not Blazor component) because HttpContext.ChallengeAsync() requires a non-circuit HTTP context. File: src/McpServer.Web/Pages/Auth/Login.cshtml + Login.cshtml.cs. Must add AddRazorPages() + MapRazorPages() to Program.cs.' - - 'MISSING - Logout flow: CookieAuthenticationDefaults.LogoutPath=/logout but no page exists. Razor Page that calls HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme) then HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme) to trigger provider end_session redirect. File: src/McpServer.Web/Pages/Auth/Logout.cshtml + Logout.cshtml.cs.' - - 'MISSING - AccessDenied page: AccessDeniedPath=/access-denied but no page exists. A simple Blazor component page (Pages/Auth/AccessDenied.razor) with Primer CSS styling and a link back to dashboard. No HttpContext needed.' - - 'MISSING - Routes.razor: Uses RouteView which ignores [Authorize] attributes. Must switch to AuthorizeRouteView with a NotAuthorized block that redirects to /login for unauthenticated users and shows access-denied for authenticated-but-unauthorized users.' - - "MISSING - User identity display: MainLayout.razor and NavMenu.razor have no user identity section. Need an AuthorizeView-based header/nav block showing the logged-in username (from context.User.Identity.Name or 'name' claim) and a logout link when authenticated, plus a login link when anonymous." - - 'MISSING - WebRoleContext: ServiceCollectionExtensions.AddUiCore() defaults to AllowAllRoleContext. McpServer.Web must register a concrete WebRoleContext : IRoleContext that reads from IHttpContextAccessor.HttpContext.User (IsAuthenticated, ClaimsPrincipal.IsInRole). File: src/McpServer.Web/Authorization/WebRoleContext.cs. Register before AddUiCore() in WebServiceRegistration.cs via services.AddHttpContextAccessor() + services.TryAddSingleton().' - - "MISSING - WebMcpContext token forwarding: EnsureInitializedAsync currently auto-discovers API key via client.InitializeAsync(). When a user is authenticated, their OIDC access_token (saved via options.SaveTokens=true) should be forwarded as Bearer token to the McpServer API. Inject IHttpContextAccessor, call HttpContext.GetTokenAsync('access_token') on each scoped request, and set client.BearerToken. The BearerToken check in EnsureInitializedAsync already short-circuits initialization if a bearer token is set." - - 'MISSING - appsettings.json McpServer section: WebMcpContext reads McpServer:BaseUrl, McpServer:ApiKey, McpServer:WorkspacePath from IConfiguration but appsettings.json has no McpServer section. Add defaults: BaseUrl=http://localhost:7147, ApiKey=(empty), WorkspacePath=(empty).' - - 'MISSING - appsettings.Development.json: Create with Authority overriding to http://localhost:7080/realms/mcp (Keycloak dev), ClientId=mcp-web, and RequireAuthenticatedUserByDefault=true for dev.' - - 'MISSING - McpServer.Web.Tests: tests/McpServer.Web.Tests/ directory is empty. McpServer.Web.Tests.csproj exists per commit history but has no content. Need WebApplicationFactory-based or Bunit-based tests covering: Login challenge redirect, Logout sign-out, AccessDenied rendering, AuthorizeRouteView blocking, WebRoleContext claim reading, bearer token forwarding.' - - 'Build verification: dotnet build src/McpServer.Web -c Debug. Test verification: dotnet test tests/McpServer.Web.Tests -c Debug. Must fix all compilation errors before marking done.' - - 'Keycloak integration context: Keycloak is on :7080, MCP API on :7147, MCP Web (Blazor) on :7100 or similar separate port. OIDC proxy routes (/auth/config, /auth/device, /auth/token) on the MCP API server are for Android/device-flow clients, not the web browser flow. Web UI uses standard browser-based Authorization Code flow (PKCE optional, code response type already configured).' - - "Role claim mapping: MapInboundClaims=false, RoleClaimType='role' (per appsettings.json ClaimMapping). Keycloak emits realm roles as 'realm_access.roles' by default. An OnTokenValidated event handler may be needed to flatten realm_access.roles into individual 'role' claims - or configure Keycloak client to include roles as flat claims. This is a Keycloak client mapper configuration concern, but must be tested." - functional-requirements: - - FR-MCP-031 - implementation-tasks: - - task: 'Task A1 - Add Razor Pages infrastructure: in Program.cs add builder.Services.AddRazorPages() BEFORE builder.Build(), and add app.MapRazorPages() AFTER app.UseAuthorization(). This is required to host the non-interactive Login.cshtml and Logout.cshtml pages that need HttpContext.ChallengeAsync/SignOutAsync.' - done: true - - task: "Task A2 - Create src/McpServer.Web/Pages/Auth/Login.cshtml: non-interactive Razor Page. PageModel.OnGet() calls Challenge(new AuthenticationProperties { RedirectUri = returnUrl ?? '/' }, OpenIdConnectDefaults.AuthenticationScheme) and returns the challenge result. Accepts optional 'returnUrl' query param and validates it is local. Add @page '/login' directive." - done: true - - task: 'Task A3 - Create src/McpServer.Web/Pages/Auth/Login.cshtml.cs: LoginModel : PageModel. Inject nothing beyond PageModel. OnGet(string? returnUrl) validates returnUrl is a local URL (Url.IsLocalUrl), constructs AuthenticationProperties with RedirectUri, returns Challenge(properties, OpenIdConnectDefaults.AuthenticationScheme). No Blazor component - must be a pure Razor Page.' - done: true - - task: "Task A4 - Create src/McpServer.Web/Pages/Auth/Logout.cshtml: non-interactive Razor Page. PageModel.OnGet() calls HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme) then HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = '/' }). This triggers the provider end_session redirect if configured. Add @page '/logout' directive." - done: true - - task: "Task A5 - Create src/McpServer.Web/Pages/Auth/Logout.cshtml.cs: LogoutModel : PageModel. OnGetAsync() calls await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme) then returns await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = '/' }). Both schemes must be signed out." - done: true - - task: "Task A6 - Create src/McpServer.Web/Pages/Auth/AccessDenied.razor: standard Blazor @page '/access-denied' component. Shows PrimerBlankslate with Heading='Access Denied' Description='You do not have permission to view this page.' and a link back to /dashboard. No [Authorize] on this page itself (it must be accessible without auth). No code-behind needed." - done: true - - task: "Task B1 - Update src/McpServer.Web/Routes.razor: change to . The NotAuthorized block should differentiate: if context.User.Identity?.IsAuthenticated == true redirect to /access-denied else redirect to /login with returnUrl." - done: true - - task: "Task B2 - Create src/McpServer.Web/Components/Auth/RedirectToLogin.razor: a parameter-less component that on OnInitializedAsync calls NavigationManager.NavigateTo('/login?returnUrl=' + Uri.EscapeDataString(NavigationManager.Uri), forceLoad: true). This is required because NavigateTo from inside AuthorizeRouteView must force a full page load to allow the non-circuit Razor Page to execute." - done: true - - task: "Task C1 - Update src/McpServer.Web/Components/Layout/MainLayout.razor: add block at the top of the shell. In show context.User.Identity?.Name (falling back to 'name' claim) and a link to /logout. In show a login link to /login. Add the new auth header above the