Skip to content

feat: Add get-plugin-info MCP action and improve configure-plugin usability#868

Merged
kingston merged 7 commits into
mainfrom
kingston/eng-1129-debug-why-mcp-configure-plugin-doesnt-work
Mar 23, 2026
Merged

feat: Add get-plugin-info MCP action and improve configure-plugin usability#868
kingston merged 7 commits into
mainfrom
kingston/eng-1129-debug-why-mcp-configure-plugin-doesnt-work

Conversation

@kingston

@kingston kingston commented Mar 23, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added get-plugin-info action for retrieving detailed plugin information, including configuration schema and current settings.
  • Improvements

    • Enhanced plugin configuration with automatic entity ID generation for nested entities.
    • Improved validation hints for schema fields to provide better guidance on naming conventions and field requirements.

@changeset-bot

changeset-bot Bot commented Mar 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 97a93cc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@baseplate-dev/project-builder-server Patch
@baseplate-dev/project-builder-lib Patch
@baseplate-dev/utils Patch
@baseplate-dev/create-project Patch
@baseplate-dev/project-builder-cli Patch
@baseplate-dev/project-builder-common Patch
@baseplate-dev/project-builder-dev Patch
@baseplate-dev/project-builder-web Patch
@baseplate-dev/plugin-auth Patch
@baseplate-dev/plugin-email Patch
@baseplate-dev/plugin-observability Patch
@baseplate-dev/plugin-payments Patch
@baseplate-dev/plugin-queue Patch
@baseplate-dev/plugin-rate-limit Patch
@baseplate-dev/plugin-storage Patch
@baseplate-dev/code-morph Patch
@baseplate-dev/core-generators Patch
@baseplate-dev/fastify-generators Patch
@baseplate-dev/react-generators Patch
@baseplate-dev/sync Patch
@baseplate-dev/ui-components Patch
@baseplate-dev/project-builder-test Patch
@baseplate-dev/tools Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Mar 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • examples/todo-with-better-auth/baseplate/snapshots/root/diffs/pnpm-workspace.yaml.diff is excluded by !**/baseplate/snapshots/**
  • examples/todo-with-better-auth/baseplate/snapshots/root/manifest.json is excluded by !**/baseplate/snapshots/**

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4e879041-f64a-456e-a52f-4fca47dbb4ba

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR establishes a validation hint and schema description registry system across the codebase, introduces a new get-plugin-info MCP action for retrieving plugin details with config schemas, refactors the configure-plugin action to use automated entity ID assignment, and updates supporting utilities for schema-to-TypeScript conversion and parser exports.

Changes

Cohort / File(s) Summary
Documentation & Metadata
.agents/mcp-actions.md, .changeset/add-get-plugin-info-mcp-action.md, examples/todo-with-better-auth/pnpm-workspace.yaml, package.json
Added MCP action documentation entry, created changeset for patch release across three packages, configured workspace allowBuilds restrictions, and appended success message to check:common script.
Validation & Hint Registry System
packages/utils/src/validators/validation-hint-registry.ts, packages/utils/src/validators/case-validators.ts, packages/utils/src/validators/index.ts, packages/project-builder-lib/src/schema/utils/validation.ts
Introduced validationHintRegistry for registering human-readable validation hints to Zod validators; updated case validators and PASCAL/CAMEL/CONSTANT_CASE_STRING validators to register descriptions via the new registry.
Schema Description & Type Conversion
packages/project-builder-server/src/actions/definition/build-ts-description-registry.ts, packages/project-builder-server/src/actions/definition/build-ts-description-registry.unit.test.ts, packages/project-builder-server/src/actions/definition/schema-to-type-string.ts, packages/project-builder-server/src/actions/definition/schema-to-type-string.unit.test.ts
Added utilities to build TypeScript description metadata registries from Zod schemas with @ref and @entity JSDoc annotations, convert schemas to TypeScript type strings, and comprehensive unit tests validating metadata population and output formatting.
Parser & Tools Exports
packages/project-builder-lib/src/parser/index.ts, packages/project-builder-lib/src/tools/index.ts
Exported SchemaStructureVisitor type and walkSchemaStructure function from parser; explicitly re-exported assignEntityIds from tools module.
New Plugin Info Action
packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts, packages/project-builder-server/src/actions/definition/index.ts
Introduced new getPluginInfoAction service action that retrieves detailed plugin metadata, configuration schema, current configuration, enabled status, and displays human-readable output; added re-export to definition actions index.
Configure Plugin Refactor
packages/project-builder-server/src/actions/definition/configure-plugin.action.ts
Refactored plugin configuration update flow to use immer-based serialized definition construction with automated entity ID assignment; updated descriptions to clarify entity names vs. IDs and auto-generated nested IDs; added conditional logic for new vs. existing plugin detection and proper config schema handling.
Get Entity Schema Update & Action Registry
packages/project-builder-server/src/actions/definition/get-entity-schema.action.ts, packages/project-builder-server/src/actions/registry.ts
Replaced Zod-to-TypeScript conversion to use new schemaToTypeString utility; added getPluginInfoAction to USER_SERVICE_ACTIONS array.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: adding a new get-plugin-info MCP action and improving configure-plugin usability, which are reflected throughout the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kingston/eng-1129-debug-why-mcp-configure-plugin-doesnt-work

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/project-builder-lib/src/schema/utils/validation.ts (1)

17-22: Consider adding a validation hint to OPTIONAL_CONSTANT_CASE_STRING for consistency.

The other three validators in this file now have validation hints registered, but OPTIONAL_CONSTANT_CASE_STRING (lines 23-27) does not. If this is intentional because it's a compound schema with .or(z.literal('')).optional(), the current state is fine. Otherwise, consider adding a hint for completeness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/project-builder-lib/src/schema/utils/validation.ts` around lines 17
- 22, The OPTIONAL_CONSTANT_CASE_STRING schema lacks a registered validation
hint—update the OPTIONAL_CONSTANT_CASE_STRING declaration to call
.register(validationHintRegistry, { description: "CONSTANT_CASE (e.g.
'MY_CONSTANT') or empty" }) (or a similar descriptive string) so it matches the
other validators; locate the OPTIONAL_CONSTANT_CASE_STRING variable in this file
and append the .register(...) call after the existing
.or(z.literal('')).optional() chain to provide the consistent validation hint.
packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts (2)

103-106: Multiline JSON output will have inconsistent indentation.

When currentConfig is a complex object, JSON.stringify(..., null, 2) produces multiline output, but only the first line gets the prefix. This results in misaligned CLI output.

♻️ Proposed fix for consistent indentation
     if (output.currentConfig != null) {
       console.info(`  Current config:`);
-      console.info(`    ${JSON.stringify(output.currentConfig, null, 2)}`);
+      const configJson = JSON.stringify(output.currentConfig, null, 2);
+      const indentedConfig = configJson.replace(/\n/g, '\n    ');
+      console.info(`    ${indentedConfig}`);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts`
around lines 103 - 106, The console output for output.currentConfig uses
JSON.stringify(..., null, 2) but only prefixes the first line with "    ",
causing misaligned multiline output; update the block in
get-plugin-info.action.ts that logs output.currentConfig so that after calling
JSON.stringify on output.currentConfig you normalize indentation by prefixing
every line (e.g., split the string on "\n", add the "    " prefix to each line,
then join) before passing to console.info, keeping the existing log messages and
using the same variable (output.currentConfig) and surrounding console.info
calls.

99-102: Same indentation issue for multiline config schema.

The configSchema TypeScript type string may also span multiple lines for complex schemas, causing the same misaligned output issue.

♻️ Proposed fix
     if (output.configSchema) {
       console.info(`  Config schema:`);
-      console.info(`    ${output.configSchema}`);
+      const indentedSchema = output.configSchema.replace(/\n/g, '\n    ');
+      console.info(`    ${indentedSchema}`);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts`
around lines 99 - 102, The multiline configSchema string (output.configSchema)
is printed with a single-console.info call which misaligns when it contains
newlines; update the printing to split output.configSchema by '\n' and log each
line with the same indentation applied (e.g., console.info('    ' + line)) so
every line of the schema is properly indented—change the block that references
output.configSchema and the two console.info calls to iterate lines and prefix
each with the intended spaces.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/project-builder-server/src/actions/definition/configure-plugin.action.ts`:
- Around line 83-85: The code seeds existingIds only from top-level plugins and
passes that set into assignEntityIds (in the call with configSchema and
pluginConfig), which misses IDs nested elsewhere and can produce collisions; fix
by implementing a collector (e.g., collectExistingIds) that recursively
traverses the entire draft/config/plugin object graph and accumulates all string
.id values into the existingIds Set, then use that comprehensive Set when
calling assignEntityIds (update both the existingIds creation site and the call
where assignEntityIds(configSchema, pluginConfig, { isExistingId: ... }) is
invoked) so generated nested IDs are checked against all definition-wide IDs.
- Around line 139-163: The update branch currently only rewrites plugins[idx] =
{ ...plugins[idx], config: processedConfig } and so leaves configSchemaVersion
stale or sets it to undefined; compute the latest migration version via
pluginConfigService.getLastMigrationVersion(pluginMetadata.key) (move or call
the pluginConfigService lookup used in the isNew branch into the update branch
or above both branches) and when idx !== -1 include configSchemaVersion:
lastMigrationVersion in the object only if lastMigrationVersion is not undefined
(i.e. merge it into plugins[idx] when present) so existing plugin rewrites keep
configSchemaVersion in sync but do not write undefined for plugins with no
migrations.

---

Nitpick comments:
In `@packages/project-builder-lib/src/schema/utils/validation.ts`:
- Around line 17-22: The OPTIONAL_CONSTANT_CASE_STRING schema lacks a registered
validation hint—update the OPTIONAL_CONSTANT_CASE_STRING declaration to call
.register(validationHintRegistry, { description: "CONSTANT_CASE (e.g.
'MY_CONSTANT') or empty" }) (or a similar descriptive string) so it matches the
other validators; locate the OPTIONAL_CONSTANT_CASE_STRING variable in this file
and append the .register(...) call after the existing
.or(z.literal('')).optional() chain to provide the consistent validation hint.

In
`@packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts`:
- Around line 103-106: The console output for output.currentConfig uses
JSON.stringify(..., null, 2) but only prefixes the first line with "    ",
causing misaligned multiline output; update the block in
get-plugin-info.action.ts that logs output.currentConfig so that after calling
JSON.stringify on output.currentConfig you normalize indentation by prefixing
every line (e.g., split the string on "\n", add the "    " prefix to each line,
then join) before passing to console.info, keeping the existing log messages and
using the same variable (output.currentConfig) and surrounding console.info
calls.
- Around line 99-102: The multiline configSchema string (output.configSchema) is
printed with a single-console.info call which misaligns when it contains
newlines; update the printing to split output.configSchema by '\n' and log each
line with the same indentation applied (e.g., console.info('    ' + line)) so
every line of the schema is properly indented—change the block that references
output.configSchema and the two console.info calls to iterate lines and prefix
each with the intended spaces.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9c652853-f19a-41d0-8e96-eab8af5fef19

📥 Commits

Reviewing files that changed from the base of the PR and between 62fae48 and d407c81.

📒 Files selected for processing (19)
  • .agents/mcp-actions.md
  • .changeset/add-get-plugin-info-mcp-action.md
  • examples/todo-with-better-auth/pnpm-workspace.yaml
  • package.json
  • packages/project-builder-lib/src/parser/index.ts
  • packages/project-builder-lib/src/schema/utils/validation.ts
  • packages/project-builder-lib/src/tools/index.ts
  • packages/project-builder-server/src/actions/definition/build-ts-description-registry.ts
  • packages/project-builder-server/src/actions/definition/build-ts-description-registry.unit.test.ts
  • packages/project-builder-server/src/actions/definition/configure-plugin.action.ts
  • packages/project-builder-server/src/actions/definition/get-entity-schema.action.ts
  • packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts
  • packages/project-builder-server/src/actions/definition/index.ts
  • packages/project-builder-server/src/actions/definition/schema-to-type-string.ts
  • packages/project-builder-server/src/actions/definition/schema-to-type-string.unit.test.ts
  • packages/project-builder-server/src/actions/registry.ts
  • packages/utils/src/validators/case-validators.ts
  • packages/utils/src/validators/index.ts
  • packages/utils/src/validators/validation-hint-registry.ts

Comment on lines +83 to +85
return assignEntityIds(configSchema, pluginConfig, {
isExistingId: (id) => existingIds.has(id),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use definition-wide IDs when auto-generating nested entity IDs.

Line 124 only seeds existingIds from plugins[].id, and Lines 83-85 pass that straight into assignEntityIds. That leaves collisions with the rest of the draft invisible, including IDs nested under other plugins and the new plugin entity ID itself, so generated config IDs can still duplicate existing entities.

💡 Minimal fix sketch
-    const existingIds = new Set(
-      serializedPlugins.map((p) => p.id as string).filter(Boolean),
-    );
+    const existingIds = collectExistingIds(serializedDef);
+    existingIds.add(pluginEntityId);
function collectExistingIds(
  value: unknown,
  ids = new Set<string>(),
): Set<string> {
  if (Array.isArray(value)) {
    for (const item of value) collectExistingIds(item, ids);
    return ids;
  }

  if (value && typeof value === 'object') {
    const record = value as Record<string, unknown>;
    if (typeof record.id === 'string') ids.add(record.id);
    for (const child of Object.values(record)) {
      collectExistingIds(child, ids);
    }
  }

  return ids;
}

Also applies to: 124-126

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/project-builder-server/src/actions/definition/configure-plugin.action.ts`
around lines 83 - 85, The code seeds existingIds only from top-level plugins and
passes that set into assignEntityIds (in the call with configSchema and
pluginConfig), which misses IDs nested elsewhere and can produce collisions; fix
by implementing a collector (e.g., collectExistingIds) that recursively
traverses the entire draft/config/plugin object graph and accumulates all string
.id values into the existingIds Set, then use that comprehensive Set when
calling assignEntityIds (update both the existingIds creation site and the call
where assignEntityIds(configSchema, pluginConfig, { isExistingId: ... }) is
invoked) so generated nested IDs are checked against all definition-wide IDs.

Comment on lines +139 to +163
if (isNew) {
const pluginConfigService = pluginStore.use(pluginConfigSpec);
const lastMigrationVersion = pluginConfigService.getLastMigrationVersion(
pluginMetadata.key,
);
})(container.definition);

// Serialize back to name-based format
const serializedDef = serializeSchema(
container.schema,
newDefinition,
) as Record<string, unknown>;
updatedDef = produce(serializedDef, (draft) => {
const plugins = (draft.plugins ?? []) as Record<string, unknown>[];
plugins.push({
id: pluginEntityId,
name: pluginMetadata.name,
version: pluginMetadata.version,
packageName: pluginMetadata.packageName,
config: processedConfig,
configSchemaVersion: lastMigrationVersion,
});
draft.plugins = plugins;
});
} else {
updatedDef = produce(serializedDef, (draft) => {
const plugins = draft.plugins as Record<string, unknown>[];
const idx = plugins.findIndex((p) => p.id === pluginEntityId);
if (idx !== -1) {
plugins[idx] = { ...plugins[idx], config: processedConfig };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep configSchemaVersion in sync when rewriting configs.

New plugins get the latest migration version, but updates leave the previous configSchemaVersion untouched. After rewriting an existing plugin against the current schema, the saved definition can still look stale to migration code later. This branch should also avoid writing configSchemaVersion: undefined for plugins with no migrations.

💡 Minimal fix sketch
-    if (isNew) {
-      const pluginConfigService = pluginStore.use(pluginConfigSpec);
-      const lastMigrationVersion = pluginConfigService.getLastMigrationVersion(
-        pluginMetadata.key,
-      );
+    const pluginConfigService = pluginStore.use(pluginConfigSpec);
+    const lastMigrationVersion = pluginConfigService.getLastMigrationVersion(
+      pluginMetadata.key,
+    );
+
+    if (isNew) {
       updatedDef = produce(serializedDef, (draft) => {
         const plugins = (draft.plugins ?? []) as Record<string, unknown>[];
-        plugins.push({
+        const nextPlugin: Record<string, unknown> = {
           id: pluginEntityId,
           name: pluginMetadata.name,
           version: pluginMetadata.version,
           packageName: pluginMetadata.packageName,
           config: processedConfig,
-          configSchemaVersion: lastMigrationVersion,
-        });
+        };
+        if (lastMigrationVersion !== undefined) {
+          nextPlugin.configSchemaVersion = lastMigrationVersion;
+        }
+        plugins.push(nextPlugin);
         draft.plugins = plugins;
       });
     } else {
       updatedDef = produce(serializedDef, (draft) => {
         const plugins = draft.plugins as Record<string, unknown>[];
         const idx = plugins.findIndex((p) => p.id === pluginEntityId);
         if (idx !== -1) {
-          plugins[idx] = { ...plugins[idx], config: processedConfig };
+          const nextPlugin = {
+            ...plugins[idx],
+            config: processedConfig,
+          } as Record<string, unknown>;
+          if (lastMigrationVersion === undefined) {
+            delete nextPlugin.configSchemaVersion;
+          } else {
+            nextPlugin.configSchemaVersion = lastMigrationVersion;
+          }
+          plugins[idx] = nextPlugin;
         }
       });
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/project-builder-server/src/actions/definition/configure-plugin.action.ts`
around lines 139 - 163, The update branch currently only rewrites plugins[idx] =
{ ...plugins[idx], config: processedConfig } and so leaves configSchemaVersion
stale or sets it to undefined; compute the latest migration version via
pluginConfigService.getLastMigrationVersion(pluginMetadata.key) (move or call
the pluginConfigService lookup used in the isNew branch into the update branch
or above both branches) and when idx !== -1 include configSchemaVersion:
lastMigrationVersion in the object only if lastMigrationVersion is not undefined
(i.e. merge it into plugins[idx] when present) so existing plugin rewrites keep
configSchemaVersion in sync but do not write undefined for plugins with no
migrations.

@kingston kingston merged commit 8dcf7b3 into main Mar 23, 2026
11 checks passed
@kingston kingston deleted the kingston/eng-1129-debug-why-mcp-configure-plugin-doesnt-work branch March 23, 2026 15:11
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