Skip to content

Commit 297f8bc

Browse files
Merge pull request #543 from proffesor-for-testing/fix/528-mcp-in-process
chore(release): v3.10.9
2 parents 0c260a6 + 7d3e977 commit 297f8bc

35 files changed

Lines changed: 920 additions & 107 deletions

.claude/skills/skills-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@
939939
},
940940
"metadata": {
941941
"generatedBy": "Agentic QE Fleet",
942-
"fleetVersion": "3.10.8",
942+
"fleetVersion": "3.10.9",
943943
"manifestVersion": "1.4.0",
944944
"lastUpdated": "2026-04-13T00:00:00.000Z",
945945
"contributors": [

.github/workflows/mcp-tools-test.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ jobs:
141141
- uses: actions/setup-node@v4
142142
with: { node-version: '24.13.0', cache: 'npm' }
143143
- run: npm ci
144+
# C3: integration tests under tests/integration/mcp drive the BUILT
145+
# bundles (dist/cli + dist/mcp). Without this build step they were
146+
# silently skipping (describe.skipIf(!BUILT)) — a false green.
147+
- run: npm run build
144148

145149
- name: Run MCP integration tests
146150
run: |
@@ -155,7 +159,9 @@ jobs:
155159
exit $EXIT
156160
env:
157161
NODE_OPTIONS: '--max-old-space-size=1024'
158-
continue-on-error: true
162+
# C3: was `continue-on-error: true`, which let real failures pass as
163+
# green. Removed so this job is an actual gate. The exit-124 hang
164+
# tolerance above still absorbs the known vitest-hang flake.
159165

160166
- name: Generate test report
161167
uses: dorny/test-reporter@v1

CHANGELOG.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,43 @@ All notable changes to the Agentic QE project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [3.10.8] - 2026-06-16
8+
## [3.10.9] - 2026-06-17
9+
10+
MCP server reliability and database-free completeness, all from community-reported
11+
issues (@nagoodman). The `agentic-qe mcp` command now serves real MCP clients, a
12+
stale-cache bug that made `memory_delete` look broken is fixed, database-free mode
13+
now reaches every editor's MCP config, and a new opt-in lets you install for a
14+
single platform without the Claude Code surface.
15+
16+
### Added
17+
18+
- **`--no-claude` exclusive install mode** — `aqe init --no-claude --with-<platform>`
19+
suppresses the default Claude Code surface (`.claude/`, `.mcp.json`, `CLAUDE.md`,
20+
governance, hooks) so the `--with-*` flags become the only install targets — e.g.
21+
a clean OpenCode-only project. Opt-in; the default install is unchanged. (#532)
22+
23+
### Fixed
24+
25+
- **`agentic-qe mcp` now works with programmatic MCP clients.** The command
26+
double-spawned the server with inherited stdio, so a piped-stdin client received
27+
EOF right after `initialize` and never got `tools/list`. The server now runs
28+
in-process (like the `aqe-mcp` bin), and a failed startup exits non-zero instead
29+
of hanging. (#528)
30+
- **`memory_delete` is no longer masked by a stale cached read.** Delete worked, but
31+
the session cache served a stale `memory_retrieve` afterward (the tell-tale
32+
identical timestamp), making delete look like a no-op. Mutating tools now
33+
invalidate their domain's cached reads. (#535)
34+
- **Database-free mode reaches every MCP config, not just OpenCode.** `--no-database`
35+
now propagates `AQE_MEMORY_BACKEND=memory` to `.mcp.json` (Claude Code), Cursor,
36+
Cline, Continue.dev, Kilo Code, Roo Code, Windsurf, Codex, Copilot, and Kiro — so
37+
launching the server through any client no longer recreates `.agentic-qe/memory.db`
38+
at runtime. The default persistent backend is unchanged. (#533)
39+
40+
### Changed
41+
42+
- **`js-yaml` dev dependency bumped to 4.2.0.** (#540)
43+
44+
945

1046
A database-free OpenCode install and a set of MCP stdio client-compatibility
1147
fixes (community contribution from @nagoodman), plus a dependency-security pass

docs/metaharness/05-cross-pollination-goap-plan.md

Lines changed: 215 additions & 0 deletions
Large diffs are not rendered by default.

docs/releases/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All Agentic QE release notes organized by version.
44

55
| Version | Date | Highlights |
66
|---------|------|------------|
7+
| [v3.10.9](v3.10.9.md) | 2026-06-17 | MCP reliability + db-free completeness (@nagoodman): `agentic-qe mcp` runs in-process so real clients get `tools/list` (#528); `memory_delete` no longer masked by stale session cache (#535); `--no-database` reaches all editor MCP configs (#533); new `--no-claude` exclusive install (#532). |
78
| [v3.10.8](v3.10.8.md) | 2026-06-16 | Database-free OpenCode install (`--no-database`/`--memory memory`, #530/#534) + MCP stdio client-compat fixes (#527 stdout purity + negotiated protocol, #529 loadable OpenCode assets) from @nagoodman; cleared protobufjs + ws production CVEs; vite → 8.0.16. |
89
| [v3.10.7](v3.10.7.md) | 2026-06-12 | Learning-integrity + supply chain: fix silent self-learning loss (hook swallowed native-binary errors; SONA reward feedback was inert, fixed via `@ruvector/sona` 0.1.7); shift-left consumer-tarball audit gate; refresh QE skill evals to current models. |
910
| [v3.10.6](v3.10.6.md) | 2026-06-11 | Pattern Space cross-pollination (#522): evidence-class labels on findings, pass/fail safety eval for data-protection rules, shipped-agent invariant CI, benchmark lineage + interaction benchmark, kept-nulls learning. ADR-105–110. |

docs/releases/v3.10.9.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# v3.10.9 Release Notes
2+
3+
**Release Date:** 2026-06-17
4+
5+
## Highlights
6+
7+
MCP server reliability and database-free completeness, all from community-reported
8+
issues (@nagoodman): `agentic-qe mcp` now serves real MCP clients, a stale-cache bug
9+
that made `memory_delete` look broken is fixed, database-free mode now reaches every
10+
editor's MCP config, and a new opt-in installs for a single platform without the
11+
Claude Code surface.
12+
13+
## Added
14+
15+
- **`--no-claude` exclusive install mode**`aqe init --no-claude --with-<platform>`
16+
suppresses the default Claude Code surface (`.claude/` skills+agents, `.mcp.json`,
17+
`CLAUDE.md`, governance, hooks) so the `--with-*` flags become the only install
18+
targets — e.g. a clean OpenCode-only project. Opt-in; the default install is
19+
byte-for-byte unchanged. (#532)
20+
21+
## Fixed
22+
23+
- **`agentic-qe mcp` now works with programmatic MCP clients.** The subcommand
24+
double-spawned the server with inherited stdio, so a piped-stdin client received
25+
`stdin-eof` immediately after answering `initialize` and never received
26+
`tools/list`. The server now runs **in-process** (matching the working `aqe-mcp`
27+
bin), and a failed startup exits non-zero instead of hanging. (#528)
28+
- **`memory_delete` is no longer masked by a stale cached read.** The delete itself
29+
always worked — but `memory_retrieve` is cacheable, and a delete didn't invalidate
30+
the cached read, so a follow-up retrieve served the stale "found" entry (the
31+
tell-tale identical timestamp). Mutating tools now invalidate their domain's cached
32+
reads. (#535)
33+
- **Database-free mode reaches every MCP config, not just OpenCode.** `aqe init
34+
--no-database` now propagates `AQE_MEMORY_BACKEND=memory` to `.mcp.json` (Claude
35+
Code), Cursor, Cline, Continue.dev (including the merge-into-existing path), Kilo
36+
Code, Roo Code, Windsurf, Codex, Copilot, and Kiro — so launching the server
37+
through any client no longer recreates `.agentic-qe/memory.db` at runtime. The
38+
default persistent backend is unchanged. (#533)
39+
40+
## Changed
41+
42+
- **`js-yaml` dev dependency bumped to 4.2.0** (Dependabot, with the lockfile's pruned
43+
optional platform binaries restored). (#540)
44+
45+
## Notes
46+
47+
The in-process MCP fix (#528) and the cache fix (#535) ship with integration tests
48+
that drive the real protocol server, and those tests now run in CI (a prior gap where
49+
they silently skipped without a build step has been closed).

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "agentic-qe",
3-
"version": "3.10.8",
3+
"version": "3.10.9",
44
"description": "Agentic Quality Engineering V3 - Domain-Driven Design Architecture with 13 Bounded Contexts, O(log n) coverage analysis, ReasoningBank learning, 60 specialized QE agents, mathematical Coherence verification, deep Claude Flow integration",
55
"type": "module",
66
"main": "./dist/index.js",
@@ -66,7 +66,7 @@
6666
"test:all": "npm test -- --run",
6767
"test:mcp": "npm run test:unit:mcp",
6868
"test:mcp:integration": "npm test -- --run tests/integration/mcp/",
69-
"test:integration:fast": "NODE_OPTIONS='--max-old-space-size=2048 --expose-gc' vitest run tests/integration/mcp/fleet-init-wires-daemon.test.ts tests/integration/workers/workers-reach-domains.test.ts tests/integration/learning/coordinator-roundtrip.test.ts tests/integration/bridge/bridge-end-to-end.test.ts",
69+
"test:integration:fast": "NODE_OPTIONS='--max-old-space-size=2048 --expose-gc' vitest run tests/integration/mcp/fleet-init-wires-daemon.test.ts tests/integration/mcp/mcp-cli-inprocess.test.ts tests/integration/mcp/memory-delete-cache-invalidation.test.ts tests/integration/workers/workers-reach-domains.test.ts tests/integration/learning/coordinator-roundtrip.test.ts tests/integration/bridge/bridge-end-to-end.test.ts",
7070
"test:integration": "NODE_OPTIONS='--max-old-space-size=4096 --expose-gc' vitest run tests/integration/ --exclude='**/browser/**' --exclude='**/browser-integration/**' --exclude='**/*.e2e.test.ts'",
7171
"mcp:validate": "node scripts/smoke-mcp-protocol.mjs",
7272
"mcp:parity": "node scripts/audit-mcp-tool-parity.mjs",

src/cli/commands/mcp.ts

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010
*/
1111

1212
import { Command } from 'commander';
13-
import { spawn } from 'child_process';
1413
import { join, dirname } from 'path';
1514
import { existsSync } from 'fs';
16-
import { fileURLToPath } from 'url';
15+
import { fileURLToPath, pathToFileURL } from 'url';
1716
import { findPackageRoot } from '../../init/find-package-root.js';
1817

1918
/**
@@ -25,14 +24,11 @@ export function createMcpCommand(): Command {
2524
.option('--http <port>', 'Also start HTTP server for AG-UI/A2A protocols', '0')
2625
.option('--verbose', 'Enable verbose logging')
2726
.action(async (options) => {
28-
// Set up environment
29-
const env: Record<string, string> = {
30-
...process.env as Record<string, string>,
31-
AQE_HTTP_PORT: options.http || '0',
32-
};
33-
27+
// Configure the server via env BEFORE importing the entry — entry.ts
28+
// reads these at startup.
29+
process.env.AQE_HTTP_PORT = options.http || '0';
3430
if (options.verbose) {
35-
env.AQE_VERBOSE = 'true';
31+
process.env.AQE_VERBOSE = 'true';
3632
}
3733

3834
// Find the MCP entry point
@@ -44,32 +40,31 @@ export function createMcpCommand(): Command {
4440
process.exit(1);
4541
}
4642

47-
// Determine how to run the entry point
48-
const isBundle = entryPath.endsWith('.js');
49-
const command = 'node';
50-
const args = isBundle
51-
? [entryPath]
52-
: ['--import', 'tsx', entryPath];
53-
54-
// Spawn the MCP server, inheriting stdio for JSON-RPC communication
55-
const child = spawn(command, args, {
56-
env,
57-
stdio: 'inherit',
58-
cwd: process.cwd(),
59-
});
60-
61-
child.on('error', (error) => {
62-
console.error('Failed to start MCP server:', error.message);
43+
// Run the MCP server IN-PROCESS instead of spawning a child (issue #528).
44+
//
45+
// The old path spawned `node <entry>` with stdio:'inherit'. With a piped
46+
// stdin (any programmatic MCP client), the grandchild saw `stdin-eof`
47+
// immediately after answering `initialize` and the Issue #513 stdin-EOF
48+
// guard in entry.ts shut it down before it could serve `tools/list`.
49+
// Importing the entry runs its top-level `main()`, which starts the
50+
// server on THIS process's real stdio and installs its own
51+
// signal/stdin shutdown handlers. The dynamic import resolves as soon as
52+
// module evaluation kicks off `main()`; the server then keeps the
53+
// process alive on stdin. This matches the working `aqe-mcp` bin, which
54+
// runs the bundle directly.
55+
try {
56+
await import(pathToFileURL(entryPath).href);
57+
} catch (error) {
58+
console.error('Failed to start MCP server:', (error as Error).message);
6359
process.exit(1);
64-
});
65-
66-
child.on('exit', (code) => {
67-
process.exit(code ?? 0);
68-
});
60+
}
6961

70-
// Forward signals to child
71-
process.on('SIGINT', () => child.kill('SIGINT'));
72-
process.on('SIGTERM', () => child.kill('SIGTERM'));
62+
// entry.ts kicks off `main()` fire-and-forget, so the import above
63+
// resolves while the server's async init is still in flight. Keep this
64+
// action pending forever so the CLI wrapper doesn't return (and exit)
65+
// out from under the server. entry.ts owns shutdown — its signal and
66+
// stdin-EOF handlers call process.exit when the client disconnects.
67+
await new Promise<never>(() => { /* server owns the process lifecycle */ });
7368
});
7469

7570
return cmd;

src/cli/handlers/init-handler.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export class InitHandler implements ICommandHandler {
7272
.option('--with-claude-flow', 'Force Claude Flow integration setup')
7373
.option('--skip-claude-flow', 'Skip Claude Flow integration')
7474
.option('--no-governance', 'Skip governance configuration (ADR-058)')
75+
.option('--no-claude', 'Suppress the default Claude Code surface (.claude/, .mcp.json, CLAUDE.md, governance, hooks) so --with-<platform> flags are the only install targets (#532)')
7576
.option('--modular', 'Use new modular init system (default for --auto)')
7677
.action(async (options) => {
7778
await this.execute(options, context);
@@ -139,8 +140,13 @@ export class InitHandler implements ICommandHandler {
139140
options.withWindsurf || options.withContinuedev || options.withAllPlatforms
140141
);
141142
const databaseFree = options.database === false || options.memory === 'memory';
143+
// #532: `--no-claude` (commander negatable → options.claude === false) is
144+
// only honored by the modular orchestrator. Route there too, or the flag
145+
// silently falls through to runStandardInit and installs the full Claude
146+
// surface it was meant to suppress.
147+
const noClaudeRequested = options.claude === false;
142148

143-
if (options.modular || platformRequested || databaseFree) {
149+
if (options.modular || platformRequested || databaseFree || noClaudeRequested) {
144150
console.log(chalk.blue('\n Agentic QE v3 Initialization\n'));
145151
await this.runModularInit(options, context);
146152
return;
@@ -168,6 +174,23 @@ export class InitHandler implements ICommandHandler {
168174
}
169175
}
170176

177+
// #532: `--no-claude` suppresses the default Claude Code surface so the
178+
// `--with-<platform>` flags become the only targets. Commander maps the
179+
// negatable flag to `options.claude === false`. Warn if it would produce an
180+
// empty install (no platform selected) so the user isn't surprised.
181+
const noClaude = options.claude === false;
182+
if (noClaude) {
183+
const anyPlatform = Boolean(
184+
options.withOpencode || options.withN8n || options.withKiro ||
185+
options.withCopilot || options.withCursor || options.withCline ||
186+
options.withKilocode || options.withRoocode || options.withCodex ||
187+
options.withWindsurf || options.withContinuedev || options.withAllPlatforms,
188+
);
189+
if (!anyPlatform && !isJsonMode) {
190+
console.log(chalk.yellow(' --no-claude set without any --with-<platform>: this install will write almost nothing.\n'));
191+
}
192+
}
193+
171194
const { createModularInitOrchestrator } = await import('../../init/orchestrator.js');
172195
const orchestrator = createModularInitOrchestrator({
173196
projectRoot: process.cwd(),
@@ -189,6 +212,7 @@ export class InitHandler implements ICommandHandler {
189212
withContinueDev: options.withContinuedev,
190213
noMcp: options.noMcp && !options.withMcp,
191214
noGovernance: options.noGovernance,
215+
noClaude,
192216
memoryBackend: memoryOnly ? 'memory' : undefined,
193217
});
194218

@@ -617,6 +641,8 @@ interface InitOptions {
617641
withClaudeFlow?: boolean;
618642
skipClaudeFlow?: boolean;
619643
noGovernance?: boolean;
644+
/** commander negatable flag: `--no-claude` sets this to false (#532). */
645+
claude?: boolean;
620646
modular?: boolean;
621647
}
622648

0 commit comments

Comments
 (0)