@ryuenn3123/agentic-senior-core 2.0.8 → 2.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.cursorrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.0.8
3
+ Generated by Agentic-Senior-Core CLI v2.0.9
4
4
  Timestamp: 2026-04-08T14:58:53.570Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/.windsurfrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.0.8
3
+ Generated by Agentic-Senior-Core CLI v2.0.9
4
4
  Timestamp: 2026-04-08T14:58:53.570Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/README.md CHANGED
@@ -121,8 +121,23 @@ The CLI is smart. It auto-detects your current development stack, helps you buil
121
121
 
122
122
  Important behavior:
123
123
  - `init` does not copy repository workflows from this project into your target repository.
124
- - MCP server registration is manual in IDE settings.
125
- - If you want the MCP file scaffold, run `init` with `--mcp-template`.
124
+ - MCP server registration and trust/start are managed manually in IDE settings.
125
+ - If you want the MCP workspace scaffold, run `init` with `--mcp-template` (creates `.vscode/mcp.json`).
126
+
127
+ ### MCP Setup in VS Code (No File Picker)
128
+
129
+ If you are looking for a file picker in the MCP UI, that is expected because VS Code uses MCP server registration, not generic JSON file import.
130
+
131
+ 1. Generate workspace MCP config:
132
+
133
+ ```bash
134
+ npx @ryuenn3123/agentic-senior-core init --mcp-template
135
+ ```
136
+
137
+ 2. Open Command Palette and run `MCP: Open Workspace Folder Configuration`.
138
+ 3. Confirm the file is `.vscode/mcp.json` with server `agentic-senior-core`.
139
+ 4. The generated server command is `npx -y @ryuenn3123/agentic-senior-core mcp`.
140
+ 5. Open Chat Customizations > MCP Servers, then trust/start the server.
126
141
 
127
142
  If you are totally new to concepts like blueprints and guardrails, no problem — just run:
128
143
  ```bash
@@ -270,8 +285,8 @@ Our documentation has shifted into dedicated tracks to keep this README light:
270
285
  - **Automated Guardrails:** CI blueprints include LLM-as-a-Judge flow using `pr-checklist.md`.
271
286
  - **Pre-Publish Safety:** Built-in forbidden content checks detect hardcoded secrets and stray debugger artifacts before hitting the NPM registry.
272
287
  - **Machine-Readable CI Output:** LLM Judge emits `JSON_REPORT` payloads and writes `.agent-context/state/llm-judge-report.json` for PR/MR annotation tooling.
273
- - **MCP Self-Healing Loop:** `mcp.json` defines diagnostics + fix proposal workflow when lint/CI fails.
274
- - **MCP Registration Model:** IDE MCP server registration is manual; `mcp.json` is an optional template file (`--mcp-template`).
288
+ - **MCP Runtime Server:** `scripts/mcp-server.mjs` exposes validate/test/release checks as MCP tools.
289
+ - **MCP Registration Model:** IDE MCP server registration is manual; workspace config lives in `.vscode/mcp.json` (`--mcp-template`).
275
290
 
276
291
  ---
277
292
 
@@ -282,7 +297,9 @@ Our documentation has shifted into dedicated tracks to keep this README light:
282
297
  ├── .cursorrules # Dynamic compiled governance entry point
283
298
  ├── .windsurfrules # Dynamic compiled governance entry point
284
299
  ├── .agent-override.md # Team-specific exceptions (scoped + expiry)
285
- ├── mcp.json # Optional MCP template file (copied with --mcp-template)
300
+ ├── mcp.json # Governance metadata and knowledge-layer contract
301
+ ├── .vscode/
302
+ │ └── mcp.json # VS Code MCP workspace server configuration
286
303
  ├── AGENTS.md # Universal agent discovery
287
304
  ├── .github/copilot-instructions.md # GitHub Copilot entry point
288
305
  ├── .gemini/instructions.md # Antigravity / Gemini entry point
@@ -300,6 +317,7 @@ Our documentation has shifted into dedicated tracks to keep this README light:
300
317
  ├── scripts/
301
318
  │ ├── validate.mjs # Repository validator
302
319
  │ ├── llm-judge.mjs # LLM-as-a-Judge CI gate
320
+ │ ├── mcp-server.mjs # Local MCP stdio server (validate/test/release tools)
303
321
  │ ├── init-project.sh # GitHub bootstrap script (Linux/macOS)
304
322
  │ └── init-project.ps1 # GitHub bootstrap script (Windows)
305
323
  ├── docs/
@@ -11,6 +11,7 @@ import { CLI_VERSION } from '../lib/cli/constants.mjs';
11
11
  import { printUsage } from '../lib/cli/utils.mjs';
12
12
  import { runLaunchCommand } from '../lib/cli/commands/launch.mjs';
13
13
  import { runRollbackCommand } from '../lib/cli/commands/rollback.mjs';
14
+ import { runMcpServerCommand } from '../lib/cli/commands/mcp.mjs';
14
15
  import { runOptimizeCommand, parseOptimizeArguments } from '../lib/cli/commands/optimize.mjs';
15
16
  import { runInitCommand, parseInitArguments } from '../lib/cli/commands/init.mjs';
16
17
  import { runUpgradeCommand, parseUpgradeArguments } from '../lib/cli/commands/upgrade.mjs';
@@ -63,6 +64,11 @@ async function main() {
63
64
  return;
64
65
  }
65
66
 
67
+ if (commandArgument === 'mcp') {
68
+ await runMcpServerCommand();
69
+ return;
70
+ }
71
+
66
72
  console.error(`Unknown command: ${commandArgument}`);
67
73
  printUsage();
68
74
  exit(1);
@@ -429,7 +429,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
429
429
  console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
430
430
  console.log('- Generated files: .cursorrules, .windsurfrules, and .agent-context/state/onboarding-report.json');
431
431
  console.log(`- Repository workflows copied: no (workflows remain source-repo assets)`);
432
- console.log(`- MCP template file: ${shouldIncludeMcpTemplate ? 'copied (mcp.json)' : 'not copied by default (use --mcp-template)'}`);
432
+ console.log(`- MCP template file: ${shouldIncludeMcpTemplate ? 'created (.vscode/mcp.json)' : 'not created by default (use --mcp-template)'}`);
433
433
  if (isTokenOptimizationEnabled) {
434
434
  console.log(`- Token optimization policy: enabled for ${selectedTokenAgentName}`);
435
435
  } else {
@@ -0,0 +1,3 @@
1
+ export async function runMcpServerCommand() {
2
+ await import('../../../scripts/mcp-server.mjs');
3
+ }
package/lib/cli/utils.mjs CHANGED
@@ -31,6 +31,7 @@ export function printUsage() {
31
31
  console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>]');
32
32
  console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes] [--mcp-template]');
33
33
  console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
34
+ console.log(' agentic-senior-core mcp');
34
35
  console.log(' agentic-senior-core rollback [target-directory]');
35
36
  console.log(' agentic-senior-core skill [domain] [--tier <standard|advance|expert|above>] [--json]');
36
37
  console.log(' agentic-senior-core --version');
@@ -48,7 +49,7 @@ export function printUsage() {
48
49
  console.log(' --token-optimize Explicitly enable token optimization policy during init (default behavior)');
49
50
  console.log(' --token-agent Set token optimization agent target (copilot, claude, cursor, windsurf, gemini, codex, cline)');
50
51
  console.log(' --no-token-optimize Disable token optimization policy during init');
51
- console.log(' --mcp-template Also copy mcp.json template (MCP server registration in IDE is still manual)');
52
+ console.log(' --mcp-template Create .vscode/mcp.json workspace template (MCP trust/start remains manual in IDE)');
52
53
  console.log(' --dry-run Preview upgrade without writing files');
53
54
  console.log(' --yes Skip confirmation prompts for upgrade');
54
55
  console.log(' --agent Target agent integration for token optimization mode');
@@ -129,14 +130,27 @@ export async function copyGovernanceAssetsToTarget(
129
130
  }
130
131
 
131
132
  if (shouldIncludeMcpTemplate) {
132
- const sourceMcpPath = path.join(REPO_ROOT, 'mcp.json');
133
- const targetMcpPath = path.join(resolvedTargetDirectoryPath, 'mcp.json');
134
-
135
- if (
136
- await pathExists(sourceMcpPath)
137
- && path.resolve(sourceMcpPath) !== path.resolve(targetMcpPath)
138
- ) {
139
- await fs.copyFile(sourceMcpPath, targetMcpPath);
133
+ const vscodeDirectoryPath = path.join(resolvedTargetDirectoryPath, '.vscode');
134
+ const workspaceMcpConfigurationPath = path.join(vscodeDirectoryPath, 'mcp.json');
135
+
136
+ const workspaceMcpConfiguration = {
137
+ $schema: 'vscode://schemas/mcp',
138
+ servers: {
139
+ 'agentic-senior-core': {
140
+ type: 'stdio',
141
+ command: 'npx',
142
+ args: ['-y', '@ryuenn3123/agentic-senior-core', 'mcp'],
143
+ },
144
+ },
145
+ };
146
+
147
+ if (!(await pathExists(workspaceMcpConfigurationPath))) {
148
+ await ensureDirectory(vscodeDirectoryPath);
149
+ await fs.writeFile(
150
+ workspaceMcpConfigurationPath,
151
+ JSON.stringify(workspaceMcpConfiguration, null, 2) + '\n',
152
+ 'utf8'
153
+ );
140
154
  }
141
155
  }
142
156
  }
package/mcp.json CHANGED
@@ -1,5 +1,4 @@
1
1
  {
2
- "$schema": "https://modelcontextprotocol.io/schemas/mcp.json",
3
2
  "version": "1.0",
4
3
  "name": "agentic-senior-core",
5
4
  "description": "MCP configuration for governance-aware diagnostics and self-healing workflows with full knowledge injection.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "2.0.8",
3
+ "version": "2.0.9",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { spawn } from 'node:child_process';
5
+ import { dirname, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
9
+ const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
10
+ const PACKAGE_VERSION = JSON.parse(
11
+ readFileSync(resolve(REPOSITORY_ROOT, 'package.json'), 'utf8')
12
+ ).version;
13
+ const DEFAULT_PROTOCOL_VERSION = '2024-11-05';
14
+
15
+ const TEST_SUITE_ARGS = {
16
+ full: ['--test', './tests/cli-smoke.test.mjs', './tests/llm-judge.test.mjs', './tests/enterprise-ops.test.mjs', './tests/skill-tier-gate.test.mjs'],
17
+ cli: ['--test', './tests/cli-smoke.test.mjs'],
18
+ enterprise: ['--test', './tests/enterprise-ops.test.mjs'],
19
+ 'llm-judge': ['--test', './tests/llm-judge.test.mjs'],
20
+ 'skill-tier': ['--test', './tests/skill-tier-gate.test.mjs'],
21
+ };
22
+
23
+ const TOOL_DEFINITIONS = [
24
+ {
25
+ name: 'validate',
26
+ description: 'Run repository validation checks.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {},
30
+ additionalProperties: false,
31
+ },
32
+ },
33
+ {
34
+ name: 'test',
35
+ description: 'Run test suites (full or targeted).',
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ suite: {
40
+ type: 'string',
41
+ enum: ['full', 'cli', 'enterprise', 'llm-judge', 'skill-tier'],
42
+ description: 'Target test suite. Defaults to full.',
43
+ },
44
+ },
45
+ additionalProperties: false,
46
+ },
47
+ },
48
+ {
49
+ name: 'release_gate',
50
+ description: 'Run release gate checks.',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: {},
54
+ additionalProperties: false,
55
+ },
56
+ },
57
+ {
58
+ name: 'forbidden_content_check',
59
+ description: 'Run forbidden content scan used by publish gate.',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {},
63
+ additionalProperties: false,
64
+ },
65
+ },
66
+ ];
67
+
68
+ let incomingBuffer = Buffer.alloc(0);
69
+
70
+ function writeMessage(payload) {
71
+ const serializedPayload = JSON.stringify(payload);
72
+ const payloadLength = Buffer.byteLength(serializedPayload, 'utf8');
73
+ process.stdout.write(`Content-Length: ${payloadLength}\r\n\r\n${serializedPayload}`);
74
+ }
75
+
76
+ function sendResponse(id, result) {
77
+ writeMessage({
78
+ jsonrpc: '2.0',
79
+ id,
80
+ result,
81
+ });
82
+ }
83
+
84
+ function sendError(id, code, message, data) {
85
+ writeMessage({
86
+ jsonrpc: '2.0',
87
+ id,
88
+ error: {
89
+ code,
90
+ message,
91
+ data,
92
+ },
93
+ });
94
+ }
95
+
96
+ function normalizeToolName(rawToolName) {
97
+ return typeof rawToolName === 'string' ? rawToolName.trim() : '';
98
+ }
99
+
100
+ function buildCommandOutput(commandLabel, commandArguments, exitCode, stdoutContent, stderrContent) {
101
+ const outputSections = [
102
+ `Command: node ${commandArguments.join(' ')}`,
103
+ `Exit code: ${exitCode}`,
104
+ ];
105
+
106
+ if (stdoutContent.trim().length > 0) {
107
+ outputSections.push(`STDOUT:\n${stdoutContent.trimEnd()}`);
108
+ }
109
+
110
+ if (stderrContent.trim().length > 0) {
111
+ outputSections.push(`STDERR:\n${stderrContent.trimEnd()}`);
112
+ }
113
+
114
+ return [
115
+ `[${commandLabel}]`,
116
+ outputSections.join('\n\n'),
117
+ ].join('\n\n');
118
+ }
119
+
120
+ function runNodeCommand(commandLabel, commandArguments) {
121
+ return new Promise((resolveResult) => {
122
+ const childProcess = spawn(process.execPath, commandArguments, {
123
+ cwd: REPOSITORY_ROOT,
124
+ env: process.env,
125
+ });
126
+
127
+ let stdoutContent = '';
128
+ let stderrContent = '';
129
+
130
+ childProcess.stdout.on('data', (chunk) => {
131
+ stdoutContent += chunk.toString('utf8');
132
+ });
133
+
134
+ childProcess.stderr.on('data', (chunk) => {
135
+ stderrContent += chunk.toString('utf8');
136
+ });
137
+
138
+ childProcess.on('error', (error) => {
139
+ resolveResult({
140
+ content: [
141
+ {
142
+ type: 'text',
143
+ text: `[${commandLabel}] Failed to start command: ${error.message}`,
144
+ },
145
+ ],
146
+ isError: true,
147
+ });
148
+ });
149
+
150
+ childProcess.on('close', (exitCode) => {
151
+ const normalizedExitCode = typeof exitCode === 'number' ? exitCode : 1;
152
+ resolveResult({
153
+ content: [
154
+ {
155
+ type: 'text',
156
+ text: buildCommandOutput(
157
+ commandLabel,
158
+ commandArguments,
159
+ normalizedExitCode,
160
+ stdoutContent,
161
+ stderrContent
162
+ ),
163
+ },
164
+ ],
165
+ isError: normalizedExitCode !== 0,
166
+ });
167
+ });
168
+ });
169
+ }
170
+
171
+ async function executeToolCall(toolName, toolArguments = {}) {
172
+ if (toolName === 'validate') {
173
+ return runNodeCommand('validate', ['./scripts/validate.mjs']);
174
+ }
175
+
176
+ if (toolName === 'test') {
177
+ const requestedSuite = typeof toolArguments.suite === 'string'
178
+ ? toolArguments.suite
179
+ : 'full';
180
+
181
+ const selectedSuite = TEST_SUITE_ARGS[requestedSuite] ? requestedSuite : 'full';
182
+ return runNodeCommand(`test:${selectedSuite}`, TEST_SUITE_ARGS[selectedSuite]);
183
+ }
184
+
185
+ if (toolName === 'release_gate') {
186
+ return runNodeCommand('release_gate', ['./scripts/release-gate.mjs']);
187
+ }
188
+
189
+ if (toolName === 'forbidden_content_check') {
190
+ return runNodeCommand('forbidden_content_check', ['./scripts/forbidden-content-check.mjs']);
191
+ }
192
+
193
+ return {
194
+ content: [
195
+ {
196
+ type: 'text',
197
+ text: `Unknown tool: ${toolName}`,
198
+ },
199
+ ],
200
+ isError: true,
201
+ };
202
+ }
203
+
204
+ async function handleRequest(requestMessage) {
205
+ const requestId = requestMessage.id;
206
+ const requestMethod = requestMessage.method;
207
+ const requestParams = requestMessage.params || {};
208
+
209
+ if (typeof requestMethod !== 'string') {
210
+ if (typeof requestId !== 'undefined') {
211
+ sendError(requestId, -32600, 'Invalid Request');
212
+ }
213
+ return;
214
+ }
215
+
216
+ if (requestMethod === 'initialize') {
217
+ const negotiatedProtocolVersion = typeof requestParams.protocolVersion === 'string'
218
+ ? requestParams.protocolVersion
219
+ : DEFAULT_PROTOCOL_VERSION;
220
+
221
+ sendResponse(requestId, {
222
+ protocolVersion: negotiatedProtocolVersion,
223
+ capabilities: {
224
+ tools: {
225
+ listChanged: false,
226
+ },
227
+ },
228
+ serverInfo: {
229
+ name: 'agentic-senior-core',
230
+ version: PACKAGE_VERSION,
231
+ },
232
+ });
233
+ return;
234
+ }
235
+
236
+ if (requestMethod === 'notifications/initialized') {
237
+ return;
238
+ }
239
+
240
+ if (requestMethod === 'ping') {
241
+ if (typeof requestId !== 'undefined') {
242
+ sendResponse(requestId, {});
243
+ }
244
+ return;
245
+ }
246
+
247
+ if (requestMethod === 'tools/list') {
248
+ sendResponse(requestId, {
249
+ tools: TOOL_DEFINITIONS,
250
+ });
251
+ return;
252
+ }
253
+
254
+ if (requestMethod === 'tools/call') {
255
+ const requestedToolName = normalizeToolName(requestParams.name);
256
+
257
+ if (!requestedToolName) {
258
+ sendError(requestId, -32602, 'Invalid params: tool name is required');
259
+ return;
260
+ }
261
+
262
+ const toolResult = await executeToolCall(requestedToolName, requestParams.arguments || {});
263
+ sendResponse(requestId, toolResult);
264
+ return;
265
+ }
266
+
267
+ if (typeof requestId !== 'undefined') {
268
+ sendError(requestId, -32601, `Method not found: ${requestMethod}`);
269
+ }
270
+ }
271
+
272
+ function readNextFramedMessage() {
273
+ const headerEndIndex = incomingBuffer.indexOf('\r\n\r\n');
274
+ if (headerEndIndex === -1) {
275
+ return null;
276
+ }
277
+
278
+ const rawHeader = incomingBuffer.slice(0, headerEndIndex).toString('utf8');
279
+ const headerLines = rawHeader.split('\r\n');
280
+ let contentLength = null;
281
+
282
+ for (const headerLine of headerLines) {
283
+ const separatorIndex = headerLine.indexOf(':');
284
+ if (separatorIndex === -1) {
285
+ continue;
286
+ }
287
+
288
+ const headerName = headerLine.slice(0, separatorIndex).trim().toLowerCase();
289
+ const headerValue = headerLine.slice(separatorIndex + 1).trim();
290
+
291
+ if (headerName === 'content-length') {
292
+ contentLength = Number.parseInt(headerValue, 10);
293
+ break;
294
+ }
295
+ }
296
+
297
+ if (!Number.isFinite(contentLength) || contentLength < 0) {
298
+ incomingBuffer = Buffer.alloc(0);
299
+ return null;
300
+ }
301
+
302
+ const bodyStartIndex = headerEndIndex + 4;
303
+ const frameEndIndex = bodyStartIndex + contentLength;
304
+
305
+ if (incomingBuffer.length < frameEndIndex) {
306
+ return null;
307
+ }
308
+
309
+ const rawMessage = incomingBuffer.slice(bodyStartIndex, frameEndIndex).toString('utf8');
310
+ incomingBuffer = incomingBuffer.slice(frameEndIndex);
311
+ return rawMessage;
312
+ }
313
+
314
+ function processIncomingBuffer() {
315
+ while (true) {
316
+ const framedMessage = readNextFramedMessage();
317
+ if (framedMessage === null) {
318
+ return;
319
+ }
320
+
321
+ let parsedRequest;
322
+ try {
323
+ parsedRequest = JSON.parse(framedMessage);
324
+ } catch {
325
+ continue;
326
+ }
327
+
328
+ Promise.resolve(handleRequest(parsedRequest)).catch((error) => {
329
+ if (typeof parsedRequest?.id !== 'undefined') {
330
+ sendError(parsedRequest.id, -32603, 'Internal error', String(error?.message || error));
331
+ }
332
+ });
333
+ }
334
+ }
335
+
336
+ process.stdin.on('data', (chunk) => {
337
+ incomingBuffer = Buffer.concat([incomingBuffer, chunk]);
338
+ processIncomingBuffer();
339
+ });
340
+
341
+ process.stdin.on('end', () => {
342
+ process.exit(0);
343
+ });
344
+
345
+ process.on('SIGINT', () => {
346
+ process.exit(0);
347
+ });
@@ -151,6 +151,7 @@ async function validateRequiredFiles() {
151
151
  'scripts/benchmark-gate.mjs',
152
152
  'scripts/benchmark-intelligence.mjs',
153
153
  'scripts/governance-weekly-report.mjs',
154
+ 'scripts/mcp-server.mjs',
154
155
  'scripts/frontend-usability-audit.mjs',
155
156
  'scripts/release-gate.mjs',
156
157
  'scripts/generate-sbom.mjs',
@@ -175,6 +176,7 @@ async function validateRequiredFiles() {
175
176
  '.agent-context/state/benchmark-watchlist.json',
176
177
  '.agent-context/state/skill-platform.json',
177
178
  '.agent-context/skills/index.json',
179
+ '.vscode/mcp.json',
178
180
  '.github/workflows/release-gate.yml',
179
181
  '.github/workflows/sbom-compliance.yml',
180
182
  '.github/workflows/benchmark-intelligence.yml',
@@ -700,6 +702,8 @@ async function validateMcpConfiguration() {
700
702
  const mcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, 'mcp.json')));
701
703
  const lintServerCommand = mcpConfiguration.servers?.lint?.command;
702
704
  const testServerCommand = mcpConfiguration.servers?.test?.command;
705
+ const workspaceMcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, '.vscode', 'mcp.json')));
706
+ const workspaceServerConfig = workspaceMcpConfiguration.servers?.['agentic-senior-core'];
703
707
 
704
708
  if (lintServerCommand === 'node') {
705
709
  pass('MCP lint server uses Node');
@@ -712,6 +716,24 @@ async function validateMcpConfiguration() {
712
716
  } else {
713
717
  fail('MCP test server must use Node');
714
718
  }
719
+
720
+ if (workspaceMcpConfiguration.$schema === 'vscode://schemas/mcp') {
721
+ pass('Workspace MCP config uses trusted VS Code schema');
722
+ } else {
723
+ fail('Workspace MCP config must use $schema: vscode://schemas/mcp');
724
+ }
725
+
726
+ if (workspaceServerConfig?.command === 'node') {
727
+ pass('Workspace MCP server command uses Node');
728
+ } else {
729
+ fail('Workspace MCP server command must use Node');
730
+ }
731
+
732
+ if (Array.isArray(workspaceServerConfig?.args) && workspaceServerConfig.args.includes('./scripts/mcp-server.mjs')) {
733
+ pass('Workspace MCP server points to scripts/mcp-server.mjs');
734
+ } else {
735
+ fail('Workspace MCP server must include ./scripts/mcp-server.mjs argument');
736
+ }
715
737
  }
716
738
 
717
739
  async function validateHumanWritingGovernance() {