Skip to content

Complete Plexus management MCP support#567

Merged
mcowger merged 3 commits into
mainfrom
feat/mcp-toggle-doc
Jun 6, 2026
Merged

Complete Plexus management MCP support#567
mcowger merged 3 commits into
mainfrom
feat/mcp-toggle-doc

Conversation

@mcowger
Copy link
Copy Markdown
Owner

@mcowger mcowger commented Jun 6, 2026

Summary

  • complete the writable Plexus management MCP surface by shimming to the existing management API
  • add bounded in-memory recent system logs plus MCP system-log and runtime log-level controls
  • update MCP docs, OpenAPI specs, frontend MCP copy, and backend test

@mcowger mcowger merged commit 6fb042e into main Jun 6, 2026
2 checks passed
@mcowger mcowger deleted the feat/mcp-toggle-doc branch June 6, 2026 05:53
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 6, 2026

Greptile Summary

This PR completes the writable Plexus management MCP surface by replacing stub implementations with a fastify.inject-based shim that routes tool calls through the existing management REST API. It also adds a bounded in-memory system-log buffer, a new /v0/system/logs/recent endpoint, runtime log-level controls, and a frontend toggle to enable/disable the Plexus Management MCP.

  • MCP shim (plexus.ts): All previously unimplemented tools now delegate to real management routes via fastify.inject, forwarding the x-admin-key header and recording every request in the MCP usage log.
  • System logs (logger.ts, system-logs.ts): Adds a 1,000-entry in-memory ring buffer captured by StreamTransport, exposed at GET /v0/system/logs/recent with a custom serializer handling circular references and Error objects.
  • Frontend (Mcp.tsx, api.ts): Adds an enable/disable toggle for the Plexus Management MCP endpoint with optimistic UI and revert-on-failure semantics.

Confidence Score: 4/5

Safe to merge. The shim correctly forwards the admin key, all new write operations go through the validated management routes, and the system-log buffer is bounded.

The shim delegation pattern is solid and the management route auth boundary is preserved. The main concerns are serializeRecentLog emitting [Circular] for multiply-referenced objects, Array.shift() being O(n) on overflow, and the system-logs test re-mocking utils/logger in violation of the project rule. None of these affect correctness of the core MCP surface or the write paths.

packages/backend/src/routes/management/tests/system-logs.test.ts (rule violation), packages/backend/src/routes/management/system-logs.ts (WeakSet false-positive), packages/backend/src/utils/logger.ts (O(n) buffer eviction)

Important Files Changed

Filename Overview
packages/backend/src/routes/mcp/plexus.ts Major expansion: all previously stub-only tools now shim to real management routes via fastify.inject. MCP usage logging added. Logic appears correct; type safety sacrificed with Promise returns but practical for this pattern.
packages/backend/src/routes/management/system-logs.ts Adds GET /v0/system/logs/recent endpoint and serializeRecentLog helper. WeakSet circular-reference detection will incorrectly label shared (non-circular) objects as [Circular], producing misleading log output.
packages/backend/src/utils/logger.ts Adds 1,000-entry in-memory ring buffer captured in StreamTransport.log. Buffer eviction uses Array.shift() which is O(n); functional but inefficient at scale.
packages/backend/src/routes/management/config.ts Adds GET/PATCH endpoints for aliases, keys, and mcp-servers that were previously write-only. Also adds GET+PATCH /v0/management/config/mcp-enabled. All new routes follow existing patterns with Zod validation and consistent error handling.
packages/backend/src/routes/management/tests/system-logs.test.ts New test for /v0/system/logs/recent. Re-mocks utils/logger with a pass-through to bypass the global mock, violating AGENTS.md. Also uses a fragile 20ms setTimeout to wait for setImmediate.
packages/backend/src/routes/mcp/tests/plexus-mcp-routes.test.ts Comprehensive expansion: mocks fastify.inject in beforeEach to simulate all management routes, covering all newly implemented tools. Uses registerSpy correctly and tests all major tool operations.
packages/frontend/src/pages/Mcp.tsx Adds Plexus Management MCP enable/disable toggle in two places. Optimistic UI with revert on failure. Clean implementation.
packages/frontend/src/lib/api.ts Adds getMcpEnabled and patchMcpEnabled API methods, following existing patterns exactly.
packages/backend/src/routes/mcp/index.ts Threads mcpUsageStorage through to registerPlexusMcpRoutes so admin MCP requests are now recorded in usage logs.

Reviews (1): Last reviewed commit: "chore(mcp): limit toggle and simplify MC..." | Re-trigger Greptile

Comment on lines +11 to +14

describe('system log routes', () => {
let fastify: FastifyInstance;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Violates project rule: do not re-mock utils/logger

AGENTS.md explicitly states "utils/logger and @earendil-works/pi-ai are globally mocked; do not re-mock them in test files." This file calls vi.mock on utils/logger (with a pass-through to the real module) precisely to bypass the global mock and use the real transport. The stated workaround may be necessary to make the real StreamTransport fire, but it still violates the project rule. Either the global mock configuration should be updated to expose clearRecentLogsForTesting, or the test approach should be aligned with how other logger-touching tests handle this.

Context Used: AGENTS.md (source)

Comment on lines +73 to +97
return {
name: value.name,
message: value.message,
stack: value.stack,
};
}

if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return '[Circular]';
}
seen.add(value);
}

return value;
})
);
} catch {
const fallback = entry as Record<string, unknown> | null;
return {
level: fallback && typeof fallback.level === 'string' ? fallback.level : 'unknown',
message:
fallback && typeof fallback.message === 'string'
? fallback.message
: '[unserializable log entry]',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 WeakSet will flag multiply-referenced objects as [Circular]

The seen set is created once per serializeRecentLog call and never reset between tree nodes. If the same object appears at two different paths in a log entry (a DAG, not a cycle), the second occurrence is replaced with '[Circular]' even though there is no circular reference. This can make log entries misleading or incomplete. A safe alternative is to use structuredClone with a try/catch before falling back to the manual replacer.

Comment on lines +16 to +21
function appendRecentLog(info: any): void {
recentLogs.push(info);
if (recentLogs.length > RECENT_LOG_BUFFER_SIZE) {
recentLogs.shift();
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Array.shift() is O(n) for a 1,000-entry buffer

Every log entry written after the buffer is full calls shift(), which moves all 1,000 remaining elements. In a high-throughput environment this will run on every write. A ring-buffer approach eliminates the linear scan. At 1,000 entries the impact is small today, but the buffer size is a named constant that could grow.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant