Skip to content

fix: update tool names to snake_case format for consistency#427

Merged
frontegg-david merged 5 commits into
mainfrom
fix/408-jobs-auto-register
May 24, 2026
Merged

fix: update tool names to snake_case format for consistency#427
frontegg-david merged 5 commits into
mainfrom
fix/408-jobs-auto-register

Conversation

@frontegg-david
Copy link
Copy Markdown
Contributor

@frontegg-david frontegg-david commented May 17, 2026

Summary by CodeRabbit

  • New Features

    • Jobs and workflows auto-enable when declared via @App; opt-in exports/subpaths expose manual job/workflow management.
  • Documentation

    • Platform docs updated to use underscore tool names (e.g., list_jobs, execute_job) and note hyphenated aliases will resolve for one release with deprecation warnings; examples and troubleshooting adjusted for auto-enable behavior.
  • Tests

    • Added/updated tests to validate underscore naming and new export paths.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

📝 Walkthrough

Walkthrough

This PR migrates MCP job and workflow tool identifiers from kebab-case naming (e.g., list-jobs, execute-job) to snake_case (e.g., list_jobs, execute_job). The PR maintains one-release backward compatibility via legacy alias fallback, expands the SDK's public tool-class surface for manual registration, refactors jobs/workflows auto-enablement from @App declarations, and updates all associated documentation and tests.

Changes

MCP Tool Naming Migration and Auto-Enablement

Layer / File(s) Summary
Tool naming migration
libs/sdk/src/job/tools/execute-job.tool.ts, libs/sdk/src/job/tools/get-job-status.tool.ts, libs/sdk/src/job/tools/list-jobs.tool.ts, libs/sdk/src/job/tools/register-job.tool.ts, libs/sdk/src/job/tools/remove-job.tool.ts, libs/sdk/src/workflow/tools/execute-workflow.tool.ts, libs/sdk/src/workflow/tools/get-workflow-status.tool.ts, libs/sdk/src/workflow/tools/list-workflows.tool.ts, libs/sdk/src/workflow/tools/register-workflow.tool.ts, libs/sdk/src/workflow/tools/remove-workflow.tool.ts
Tool decorator @Tool({ name: ... }) metadata updated across 10 job and workflow tool classes: kebab-case names (execute-job, list-jobs, etc.) changed to snake_case equivalents (execute_job, list_jobs, etc.) for consistent MCP tool registration and discovery.
SDK API surface expansion for manual tool registration
libs/sdk/package.json, libs/sdk/src/index.ts, libs/sdk/src/job/index.ts, libs/sdk/src/workflow/index.ts
Package.json exports field adds ./job/tools and ./workflow/tools subpath entry points with CommonJS, ESM, and development targets; main SDK index and job/workflow barrels re-export all tool classes to enable opt-in manual registration for users who want finer-grained control over which tools are registered.
Direct client and server tool invocation updates
libs/sdk/src/direct/direct-client.ts, libs/sdk/src/direct/direct-server.ts
DirectClientImpl methods (listJobs, executeJob, getJobStatus, listWorkflows, executeWorkflow, getWorkflowStatus) updated to invoke MCP tools using snake_case names; DirectServerImpl delegation methods similarly updated; parameter passing and return value handling unchanged.
Legacy alias fallback for one-release compatibility
libs/sdk/src/tool/flows/call-tool.flow.ts
findTool enhanced with hyphen↔underscore tool name alias resolution when no exact match is found: swaps - and _ in the requested tool name, logs a warning, and resolves the legacy-named tool for one release before breaking; preserves TOOL_NOT_FOUND for truly missing tools.
Jobs/workflows auto-enablement from @App declarations
libs/sdk/src/scope/scope.instance.ts
Scope.initialize() refactored to compute explicit vs. implicit enablement for jobs/workflows: aggregates job/workflow declarations from scope metadata and app decorators, warns if explicitly disabled while declarations exist, and derives an effectiveConfig that forces enabled=true when initialization should occur; aggregated lists passed to registerJobCapabilities instead of recomputation.
Test updates for new naming and exports
libs/sdk/src/__tests__/job-tools-exports.spec.ts, libs/sdk/src/direct/__tests__/direct-client.spec.ts
New test file (issue #408) validates tool class exports from main SDK barrel and dedicated subpath barrels, plus verifies decorator metadata uses snake_case names; DirectClient tests updated to expect snake_case tool names in callTool arguments and error messages.
Documentation updates for tool naming and auto-enablement
docs/frontmcp/deployment/mcpb.mdx, docs/frontmcp/sdk-reference/decorators/job.mdx, docs/frontmcp/sdk-reference/decorators/workflow.mdx, docs/frontmcp/sdk-reference/registries/job-registry.mdx, docs/frontmcp/sdk-reference/registries/workflow-registry.mdx, docs/frontmcp/servers/jobs.mdx, docs/frontmcp/servers/workflows.mdx, libs/skills/catalog/frontmcp-deployment/references/build-for-mcpb.md, libs/skills/catalog/frontmcp-development/references/create-job.md
Deployment and development documentation updated throughout to reflect snake_case tool names (list_jobs, execute_job, get_job_status, etc.), document one-release hyphen-alias deprecation via logging, and describe implicit jobs/workflows enablement from @App declarations with explicit opt-out and persistent storage configuration options.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DirectClientImpl
  participant MCPRegistry
  participant ToolEntry
  Client->>DirectClientImpl: listJobs / executeJob / getJobStatus (toolName: snake_case)
  DirectClientImpl->>MCPRegistry: findTool(requestedName)
  MCPRegistry->>ToolEntry: match candidate names (snake_case, legacy-kebab)
  alt resolved via legacy alias
    ToolEntry-->>MCPRegistry: matched (alias)
    MCPRegistry->>DirectClientImpl: warn deprecation -> return tool
  else direct match
    ToolEntry-->>MCPRegistry: matched (canonical)
    MCPRegistry->>DirectClientImpl: return tool
  end
  DirectClientImpl->>ToolEntry: callTool(...)
Loading

Possibly related issues

Possibly Related PRs

  • agentfront/frontmcp#255: Introduces the jobs/workflows modules and initial kebab-case tool identifiers which this PR migrates to snake_case.

Poem

🐰 Snake_case now hops through tool names bright,
Dashes retreat into the soft twilight,
One release of aliases, a kindly wink,
Auto-jobs from @App—set once, they just blink.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: renaming job and workflow tool identifiers from kebab-case (e.g., execute-job) to snake_case (e.g., execute_job) for consistency across documentation, exports, and implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/408-jobs-auto-register

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
libs/sdk/src/scope/scope.instance.ts (1)

695-784: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Extract jobs/workflows bootstrap logic out of Scope.initialize().

Line [695]-Line [784] adds a large feature-specific block inline; please move it into helper method(s) so initialize() stays orchestration-focused and easier to maintain.

♻️ Suggested extraction sketch
-    // Initialize jobs and workflows (issue `#408`).
-    // ...
-    const jobsConfig = this.metadata.jobs as JobsConfig | undefined;
-    const metaRecord = this.metadata as unknown as Record<string, unknown>;
-    const jobsList = (metaRecord['jobTypes'] as JobType[] | undefined) ?? [];
-    const workflowsList = (metaRecord['workflowTypes'] as WorkflowType[] | undefined) ?? [];
-    // ... large inline block ...
-    if (effectivelyEnabled) {
-      // ... registration ...
-    }
+    const jobsBootstrap = this.resolveJobsBootstrapState();
+    await this.initializeJobsAndWorkflows(scopeRef, jobsBootstrap);
// example helper boundaries
private resolveJobsBootstrapState(): {
  allJobs: JobType[];
  allWorkflows: WorkflowType[];
  explicitlyDisabled: boolean;
  autoEnabled: boolean;
  effectivelyEnabled: boolean;
  effectiveConfig: JobsConfig;
} { /* ... */ }

private async initializeJobsAndWorkflows(
  scopeRef: EntryOwnerRef,
  state: ReturnType<Scope['resolveJobsBootstrapState']>,
): Promise<void> { /* ... */ }

As per coding guidelines, libs/sdk/src/**/scope.instance.ts: “Keep scope.instance.ts lean by using helper functions for feature-specific registration logic (e.g., registerSkillCapabilities from skill module) instead of inlining 40+ lines”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/sdk/src/scope/scope.instance.ts` around lines 695 - 784, Extract the
inlined jobs/workflows bootstrap block out of Scope.initialize() into two
helpers: a synchronous resolveJobsBootstrapState() that computes allJobs,
allWorkflows, hasJobDeclarations, explicitlyDisabled, explicitlyEnabled,
autoEnabled, effectivelyEnabled and effectiveConfig (collecting app
jobs/workflows and metadata like the current code uses jobsConfig, metaRecord,
appJobs/appWorkflows), and an async initializeJobsAndWorkflows(scopeRef:
EntryOwnerRef, state) that performs the side-effectful logic (logging
warnings/info, constructing notifyFn, calling registerJobCapabilities, assigning
this._scopeJobs/_scopeWorkflows/_jobExecutionManager/_jobStateStore/_jobDefinitionStore,
iterating result.managementTools and creating ToolInstance via normalizeTool and
registering with this.scopeTools.registerToolInstance, and final info log).
Replace the original block in initialize() with calls to
resolveJobsBootstrapState() and, if state.effectivelyEnabled, await
initializeJobsAndWorkflows(scopeRef, state). Ensure all referenced symbols
(registerJobCapabilities, normalizeTool, ToolInstance,
scopeTools.registerToolInstance) are imported/accessible and preserve the same
logging and error handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/sdk/src/tool/flows/call-tool.flow.ts`:
- Around line 295-314: The legacy-name aliasing is only applied when searching
activeTools, so the later remote-registry fallback still uses the original name
and can return TOOL_NOT_FOUND for legacy callers; modify the lookup logic in the
call-tool flow (where variables name, activeTools, tool, alt, altMatch, and
this.logger.warn are used) to build a single list of candidate names (e.g.,
[name, alt] when /[-_]/.test(name)) and use that same candidates array for both
the activeTools search and the remote-registry lookup; keep the one-time
deprecation warning when an alias matched (this.logger.warn) and ensure the
remote lookup iterates the same candidates instead of only the original name so
legacy hyphen/underscore aliases are honored everywhere.

In `@libs/skills/catalog/frontmcp-development/references/create-job.md`:
- Around line 421-424: The docs contradict themselves: the top section says
declaring `@App`({ jobs: [...] }) auto-enables the jobs subsystem, but later
checklist/troubleshooting still requires jobs.enabled: true; update the text so
the checklist and troubleshooting reflect the auto-enable semantics — remove or
mark as optional any requirement that jobs.enabled: true unless the user is
intentionally overriding the default for persistence, and instead document that
`@FrontMcp`({ jobs }) should only be used to configure persistent stores (Redis)
or change defaults; adjust references to management tools (execute_job,
list_jobs, get_job_status, register_job, remove_job) to note they are registered
automatically when `@App`({ jobs }) or workflows are declared; apply the same
corrections to the other occurrence around lines referenced (the 638-649 block)
to keep both sections consistent.

---

Outside diff comments:
In `@libs/sdk/src/scope/scope.instance.ts`:
- Around line 695-784: Extract the inlined jobs/workflows bootstrap block out of
Scope.initialize() into two helpers: a synchronous resolveJobsBootstrapState()
that computes allJobs, allWorkflows, hasJobDeclarations, explicitlyDisabled,
explicitlyEnabled, autoEnabled, effectivelyEnabled and effectiveConfig
(collecting app jobs/workflows and metadata like the current code uses
jobsConfig, metaRecord, appJobs/appWorkflows), and an async
initializeJobsAndWorkflows(scopeRef: EntryOwnerRef, state) that performs the
side-effectful logic (logging warnings/info, constructing notifyFn, calling
registerJobCapabilities, assigning
this._scopeJobs/_scopeWorkflows/_jobExecutionManager/_jobStateStore/_jobDefinitionStore,
iterating result.managementTools and creating ToolInstance via normalizeTool and
registering with this.scopeTools.registerToolInstance, and final info log).
Replace the original block in initialize() with calls to
resolveJobsBootstrapState() and, if state.effectivelyEnabled, await
initializeJobsAndWorkflows(scopeRef, state). Ensure all referenced symbols
(registerJobCapabilities, normalizeTool, ToolInstance,
scopeTools.registerToolInstance) are imported/accessible and preserve the same
logging and error handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 003b741b-4ef6-48bb-bb09-fbb003829343

📥 Commits

Reviewing files that changed from the base of the PR and between 4328981 and 36e39c1.

⛔ Files ignored due to path filters (1)
  • libs/cli/src/commands/build/exec/cli-runtime/schema-extractor.ts is excluded by !**/build/**
📒 Files selected for processing (29)
  • docs/frontmcp/deployment/mcpb.mdx
  • docs/frontmcp/sdk-reference/decorators/job.mdx
  • docs/frontmcp/sdk-reference/decorators/workflow.mdx
  • docs/frontmcp/sdk-reference/registries/job-registry.mdx
  • docs/frontmcp/sdk-reference/registries/workflow-registry.mdx
  • docs/frontmcp/servers/jobs.mdx
  • docs/frontmcp/servers/workflows.mdx
  • libs/sdk/package.json
  • libs/sdk/src/__tests__/job-tools-exports.spec.ts
  • libs/sdk/src/direct/__tests__/direct-client.spec.ts
  • libs/sdk/src/direct/direct-client.ts
  • libs/sdk/src/direct/direct-server.ts
  • libs/sdk/src/index.ts
  • libs/sdk/src/job/index.ts
  • libs/sdk/src/job/tools/execute-job.tool.ts
  • libs/sdk/src/job/tools/get-job-status.tool.ts
  • libs/sdk/src/job/tools/list-jobs.tool.ts
  • libs/sdk/src/job/tools/register-job.tool.ts
  • libs/sdk/src/job/tools/remove-job.tool.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/sdk/src/workflow/index.ts
  • libs/sdk/src/workflow/tools/execute-workflow.tool.ts
  • libs/sdk/src/workflow/tools/get-workflow-status.tool.ts
  • libs/sdk/src/workflow/tools/list-workflows.tool.ts
  • libs/sdk/src/workflow/tools/register-workflow.tool.ts
  • libs/sdk/src/workflow/tools/remove-workflow.tool.ts
  • libs/skills/catalog/frontmcp-deployment/references/build-for-mcpb.md
  • libs/skills/catalog/frontmcp-development/references/create-job.md

Comment thread libs/sdk/src/tool/flows/call-tool.flow.ts
Comment thread libs/skills/catalog/frontmcp-development/references/create-job.md
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

Performance Test Results

Status: ✅ All tests passed

Summary

Project Tests Passed Warnings Failed Leaks
✅ demo-e2e-agents 4 4 0 0 0
✅ demo-e2e-cache 11 11 0 0 0
✅ demo-e2e-codecall 4 4 0 0 0
✅ demo-e2e-config 4 4 0 0 0
✅ demo-e2e-direct 3 3 0 0 0
✅ demo-e2e-elicitation 1 1 0 0 0
✅ demo-e2e-errors 4 4 0 0 0
✅ demo-e2e-hooks 3 3 0 0 0
✅ demo-e2e-multiapp 4 4 0 0 0
✅ demo-e2e-notifications 3 3 0 0 0
✅ demo-e2e-openapi 2 2 0 0 0
✅ demo-e2e-providers 4 4 0 0 0
✅ demo-e2e-public 4 4 0 0 0
✅ demo-e2e-redis 15 15 0 0 0
✅ demo-e2e-remember 4 4 0 0 0
✅ demo-e2e-remote 5 5 0 0 0
✅ demo-e2e-serverless 2 2 0 0 0
✅ demo-e2e-skills 15 15 0 0 0
✅ demo-e2e-standalone 2 2 0 0 0
✅ demo-e2e-transport-recreation 3 3 0 0 0
✅ demo-e2e-ui 4 4 0 0 0

Total: 101 tests across 21 projects

📊 View full report in workflow run


Generated at: 2026-05-24T12:48:10.086Z
Commit: d1a2766b

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
apps/e2e/demo-e2e-jobs/e2e/jobs-client.e2e.spec.ts (2)

113-125: ⚡ Quick win

Consider adding an e2e test for legacy alias backward compatibility.

The comment notes that hyphen forms remain callable through alias fallback, but there's no e2e test verifying this critical backward compatibility feature works across the wire.

E2E tests should validate that agents/callers using the old kebab-case names (e.g., execute-job) still function during the one-release migration period.

🧪 Proposed test for legacy alias compatibility
   });
+
+  it('should support legacy kebab-case tool names via alias fallback', async () => {
+    // Verify backward compatibility during migration period (Issue `#408`)
+    const result = await client.callTool('execute-job', {
+      name: 'greet',
+      input: { name: 'Alice' },
+      background: false,
+    });
+    const content = result.content?.find((c: { type: string }) => c.type === 'text');
+    expect(content).toBeDefined();
+    const parsed = JSON.parse(content.text);
+    expect(parsed.state).toBe('completed');
+  });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/e2e/demo-e2e-jobs/e2e/jobs-client.e2e.spec.ts` around lines 113 - 125,
Add an e2e test that verifies the legacy kebab-case tool aliases still work
end-to-end: in the existing describe block that calls client.listTools()
(referencing listTools and client), invoke the legacy names (e.g., "execute-job"
and "get-job-status") through the same client call path used by callers
(simulate an agent/caller call that resolves a tool by name) and assert the call
succeeds and returns the same behavior/result as the canonical snake_case tools
(execute_job, get_job_status); ensure the test triggers the alias fallback path
used by call-tool.flow.ts and includes assertions that both the kebab-case call
succeeds and that any returned status or output matches the snake_case
equivalent.

122-123: ⚡ Quick win

Assertions correctly updated to snake_case.

The test now expects execute_job and get_job_status, matching the renamed tool identifiers.

Consider expanding coverage to verify all 10 renamed tools appear in the listing:

  • Job tools: list_jobs, register_job, remove_job, execute_job, get_job_status
  • Workflow tools: list_workflows, register_workflow, remove_workflow, execute_workflow, get_workflow_status

This would provide more comprehensive validation of the migration.

🧪 Proposed expansion for comprehensive coverage
 it('should include job management tools in listTools', async () => {
   const tools = await client.listTools();
   const toolNames = (tools as Array<{ name: string }>).map((t) => t.name);
+  // Job management tools
+  expect(toolNames).toContain('list_jobs');
+  expect(toolNames).toContain('register_job');
+  expect(toolNames).toContain('remove_job');
   expect(toolNames).toContain('execute_job');
   expect(toolNames).toContain('get_job_status');
+  // Workflow management tools
+  expect(toolNames).toContain('list_workflows');
+  expect(toolNames).toContain('register_workflow');
+  expect(toolNames).toContain('remove_workflow');
+  expect(toolNames).toContain('execute_workflow');
+  expect(toolNames).toContain('get_workflow_status');
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/e2e/demo-e2e-jobs/e2e/jobs-client.e2e.spec.ts` around lines 122 - 123,
The test currently asserts only two snake_case tool identifiers; update the
assertions that examine the toolNames array to verify all ten renamed tools
appear by adding expects for list_jobs, register_job, remove_job, execute_job,
get_job_status, and list_workflows, register_workflow, remove_workflow,
execute_workflow, get_workflow_status (use the existing toolNames variable and
the same expect(...).toContain(...) pattern to add these checks so the spec
fully validates both Job and Workflow tool migrations).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/e2e/demo-e2e-jobs/e2e/jobs-client.e2e.spec.ts`:
- Around line 113-125: Add an e2e test that verifies the legacy kebab-case tool
aliases still work end-to-end: in the existing describe block that calls
client.listTools() (referencing listTools and client), invoke the legacy names
(e.g., "execute-job" and "get-job-status") through the same client call path
used by callers (simulate an agent/caller call that resolves a tool by name) and
assert the call succeeds and returns the same behavior/result as the canonical
snake_case tools (execute_job, get_job_status); ensure the test triggers the
alias fallback path used by call-tool.flow.ts and includes assertions that both
the kebab-case call succeeds and that any returned status or output matches the
snake_case equivalent.
- Around line 122-123: The test currently asserts only two snake_case tool
identifiers; update the assertions that examine the toolNames array to verify
all ten renamed tools appear by adding expects for list_jobs, register_job,
remove_job, execute_job, get_job_status, and list_workflows, register_workflow,
remove_workflow, execute_workflow, get_workflow_status (use the existing
toolNames variable and the same expect(...).toContain(...) pattern to add these
checks so the spec fully validates both Job and Workflow tool migrations).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5170e290-3d54-47b0-9a44-a94ad1a48ddd

📥 Commits

Reviewing files that changed from the base of the PR and between d6f6aff and befa7de.

📒 Files selected for processing (1)
  • apps/e2e/demo-e2e-jobs/e2e/jobs-client.e2e.spec.ts

@frontegg-david frontegg-david merged commit 96050e5 into main May 24, 2026
32 checks passed
@frontegg-david frontegg-david deleted the fix/408-jobs-auto-register branch May 24, 2026 12:55
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.

Job-management tools (execute_job / get_job_status / list_jobs) aren't reachable from user code

1 participant