Repository navigation
Add TypeScript capability schema definitions - #279
Conversation
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
📝 WalkthroughWalkthroughCapability JSON schemas are converted into TypeScript call-shape declarations which are attached to capability definitions and propagated through the registry, search APIs, and formatting pipeline; raw JSON schemas are included in detail output only when explicitly requested via Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant SearchTool as Search Tool
participant Registry as Capability Registry
participant Formatter as Formatter
participant CapDef as Capability Definition
Client->>SearchTool: request entity detail (detail:true, includeSchemas?: bool)
SearchTool->>Registry: searchCapabilities(query)
Registry->>CapDef: read capability specs (include input/output type defs)
CapDef-->>Registry: capability spec (with inputTypeDefinition, maybe outputTypeDefinition, maybe schemas)
Registry-->>SearchTool: search result rows (detail-mode passes includeSchemas flag)
SearchTool->>Formatter: formatEntityDetailMarkdown(detail, {includeSchemas})
Formatter-->>SearchTool: markdown + structured detail (type defs always, schemas only if includeSchemas:true)
SearchTool-->>Client: formatted markdown + structured detail
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
🔎 Preview deployed: https://kody-pr-279.kentcdodds.workers.dev Worker: Mocks:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/worker/src/mcp/capabilities/capability-search.workers.test.ts (1)
98-100: Add an explicit assertion forinputTypeDefinitionin detail-mode search results.You now provide detailed type-definition fixtures, but this test still doesn’t verify the field is returned by
searchCapabilitieswhendetail: true.Suggested assertion
expect(matches[0]?.keywords).toEqual( expect.arrayContaining(['oauth', 'redirect uri', 'provider registration']), ) +expect(matches[0]).toMatchObject({ + inputTypeDefinition: expect.stringContaining( + 'type KodyOfficialGuideInput =', + ), +}) expect(matches[0]?.outputFields).toEqual(['title', 'body'])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/worker/src/mcp/capabilities/capability-search.workers.test.ts` around lines 98 - 100, The test currently sets a detailed fixture for inputTypeDefinition but doesn’t assert it appears in the detailed search results; update the test that calls searchCapabilities with detail: true to include an explicit assertion that the returned capability object contains the inputTypeDefinition field and that its value equals the fixture string (use the same fixture value used in the test). Locate the call to searchCapabilities (with detail: true) and add an assertion against the returned result (e.g., expect(result[...].inputTypeDefinition).toEqual(...)) so the presence and exact content of inputTypeDefinition is verified.packages/worker/src/mcp/tools/search-format.ts (1)
674-682: Consider hardening markdown code-fence rendering for type definitions.If a generated type definition ever contains triple backticks, this section can break markdown structure. A dynamic or longer fence would make rendering safer.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/worker/src/mcp/tools/search-format.ts` around lines 674 - 682, The Type definitions block directly injects detail.spec.inputTypeDefinition and detail.spec.outputTypeDefinition into a fixed ``` fence which will break if those strings contain triple backticks; modify the code that emits the fence (the lines building the '```ts' and closing '```') to compute a safe fence dynamically—either by scanning detail.spec.inputTypeDefinition and detail.spec.outputTypeDefinition for the longest run of backticks and emitting a fence of backticks one character longer, or by switching to a tilde fence (e.g., ~~~) around the TypeScript content; update the section that currently references '```ts' and the closing '```' to use this dynamic/safe fence so injected code cannot terminate the block prematurely.
🤖 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/worker/src/mcp/capabilities/define-capability.ts`:
- Around line 44-56: The current truthiness checks drop a valid JSON Schema
value of false (e.g., the spread ...(outputSchema ? { outputSchema } : {}) and
the conditional that creates outputTypeDefinition), so change both checks to
explicit undefined checks: replace the first spread with ...(outputSchema !==
undefined ? { outputSchema } : {}) and change the outputTypeDefinition
conditional to use outputSchema !== undefined && definition.outputSchema (i.e.,
only test presence with !== undefined rather than truthiness) while keeping
creation via createSchemaTypeDefinition/createCapabilityTypeName as-is.
In `@packages/worker/src/mcp/capabilities/schema-type-definitions.ts`:
- Around line 82-85: The emitted composed types can be parsed with wrong
precedence (e.g., A | B & C) — update joinSchemaTypes to parenthesize composed
members before joining: after computing types via jsonSchemaToType, map each
type string to a parenthesized form when it itself contains either '|' or '&'
(and the types array length > 1), then join with the provided separator; this
ensures nested anyOf/allOf results like (A | B) & C are produced correctly while
leaving atomic types unchanged.
- Around line 119-121: The index-signature emission currently unconditionally
pushes an index signature when additionalProperties is a record, which can
conflict with previously emitted named properties; change the logic in the block
that calls isRecord(additionalProperties) and lines.push(...) so you only emit
the index signature if there are no named property lines already emitted (i.e.,
detect existing named properties in the lines array before pushing), or
alternatively widen the index signature type to include the union of named
property types; use the existing identifiers additionalProperties, isRecord,
lines and jsonSchemaToType to locate and modify the code that creates the index
signature.
---
Nitpick comments:
In `@packages/worker/src/mcp/capabilities/capability-search.workers.test.ts`:
- Around line 98-100: The test currently sets a detailed fixture for
inputTypeDefinition but doesn’t assert it appears in the detailed search
results; update the test that calls searchCapabilities with detail: true to
include an explicit assertion that the returned capability object contains the
inputTypeDefinition field and that its value equals the fixture string (use the
same fixture value used in the test). Locate the call to searchCapabilities
(with detail: true) and add an assertion against the returned result (e.g.,
expect(result[...].inputTypeDefinition).toEqual(...)) so the presence and exact
content of inputTypeDefinition is verified.
In `@packages/worker/src/mcp/tools/search-format.ts`:
- Around line 674-682: The Type definitions block directly injects
detail.spec.inputTypeDefinition and detail.spec.outputTypeDefinition into a
fixed ``` fence which will break if those strings contain triple backticks;
modify the code that emits the fence (the lines building the '```ts' and closing
'```') to compute a safe fence dynamically—either by scanning
detail.spec.inputTypeDefinition and detail.spec.outputTypeDefinition for the
longest run of backticks and emitting a fence of backticks one character longer,
or by switching to a tilde fence (e.g., ~~~) around the TypeScript content;
update the section that currently references '```ts' and the closing '```' to
use this dynamic/safe fence so injected code cannot terminate the block
prematurely.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f1d82908-cfa3-4c14-8865-09cee6b0ed26
📒 Files selected for processing (11)
docs/use/search.mdpackages/worker/src/mcp/capabilities/build-capability-registry.tspackages/worker/src/mcp/capabilities/capability-search.tspackages/worker/src/mcp/capabilities/capability-search.workers.test.tspackages/worker/src/mcp/capabilities/define-capability.tspackages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.tspackages/worker/src/mcp/capabilities/meta/meta-list-capabilities.tspackages/worker/src/mcp/capabilities/schema-type-definitions.tspackages/worker/src/mcp/capabilities/types.tspackages/worker/src/mcp/tools/search-format.node.test.tspackages/worker/src/mcp/tools/search-format.ts
| ...(outputSchema ? { outputSchema } : {}), | ||
| inputTypeDefinition: createSchemaTypeDefinition({ | ||
| jsonSchema: inputSchema, | ||
| typeName: createCapabilityTypeName(definition.name, 'Input'), | ||
| }), | ||
| ...(definition.outputSchema && outputSchema | ||
| ? { | ||
| outputTypeDefinition: createSchemaTypeDefinition({ | ||
| jsonSchema: outputSchema, | ||
| typeName: createCapabilityTypeName(definition.name, 'Output'), | ||
| }), | ||
| } | ||
| : {}), |
There was a problem hiding this comment.
Preserve explicit outputSchema: false instead of dropping it.
Line 44 and Line 49 use truthiness checks; a valid boolean JSON Schema false is treated as “absent,” so output schema/type definition get silently omitted.
💡 Proposed fix
- ...(outputSchema ? { outputSchema } : {}),
+ ...(outputSchema !== undefined ? { outputSchema } : {}),
inputTypeDefinition: createSchemaTypeDefinition({
jsonSchema: inputSchema,
typeName: createCapabilityTypeName(definition.name, 'Input'),
}),
- ...(definition.outputSchema && outputSchema
+ ...(outputSchema !== undefined
? {
outputTypeDefinition: createSchemaTypeDefinition({
jsonSchema: outputSchema,
typeName: createCapabilityTypeName(definition.name, 'Output'),
}),
}
: {}),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ...(outputSchema ? { outputSchema } : {}), | |
| inputTypeDefinition: createSchemaTypeDefinition({ | |
| jsonSchema: inputSchema, | |
| typeName: createCapabilityTypeName(definition.name, 'Input'), | |
| }), | |
| ...(definition.outputSchema && outputSchema | |
| ? { | |
| outputTypeDefinition: createSchemaTypeDefinition({ | |
| jsonSchema: outputSchema, | |
| typeName: createCapabilityTypeName(definition.name, 'Output'), | |
| }), | |
| } | |
| : {}), | |
| ...(outputSchema !== undefined ? { outputSchema } : {}), | |
| inputTypeDefinition: createSchemaTypeDefinition({ | |
| jsonSchema: inputSchema, | |
| typeName: createCapabilityTypeName(definition.name, 'Input'), | |
| }), | |
| ...(outputSchema !== undefined | |
| ? { | |
| outputTypeDefinition: createSchemaTypeDefinition({ | |
| jsonSchema: outputSchema, | |
| typeName: createCapabilityTypeName(definition.name, 'Output'), | |
| }), | |
| } | |
| : {}), |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/worker/src/mcp/capabilities/define-capability.ts` around lines 44 -
56, The current truthiness checks drop a valid JSON Schema value of false (e.g.,
the spread ...(outputSchema ? { outputSchema } : {}) and the conditional that
creates outputTypeDefinition), so change both checks to explicit undefined
checks: replace the first spread with ...(outputSchema !== undefined ? {
outputSchema } : {}) and change the outputTypeDefinition conditional to use
outputSchema !== undefined && definition.outputSchema (i.e., only test presence
with !== undefined rather than truthiness) while keeping creation via
createSchemaTypeDefinition/createCapabilityTypeName as-is.
| if (isRecord(additionalProperties)) { | ||
| lines.push(`\t[key: string]: ${jsonSchemaToType(additionalProperties)}`) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n packages/worker/src/mcp/capabilities/schema-type-definitions.ts | head -150 | tail -50Repository: kentcdodds/kody
Length of output: 1957
🏁 Script executed:
rg -l "objectSchemaToType|schema-type-definitions" --type ts --type tsx packages/worker/src/mcp/ | head -10Repository: kentcdodds/kody
Length of output: 87
🏁 Script executed:
rg -l "objectSchemaToType" packages/worker/src/mcp/ --type tsRepository: kentcdodds/kody
Length of output: 123
🏁 Script executed:
fd -e test.ts -e spec.ts packages/worker/src/mcp/ | xargs rg -l "objectSchemaToType|schema-type-definitions" 2>/dev/nullRepository: kentcdodds/kody
Length of output: 601
🏁 Script executed:
cat -n packages/worker/src/mcp/capabilities/define-capability.ts | grep -C 10 "objectSchemaToType"Repository: kentcdodds/kody
Length of output: 41
🏁 Script executed:
fd test define-capability packages/worker/Repository: kentcdodds/kody
Length of output: 5260
🏁 Script executed:
cat -n packages/worker/src/mcp/capabilities/schema-compression.node.test.ts | head -100Repository: kentcdodds/kody
Length of output: 2651
🏁 Script executed:
rg "objectSchemaToType|jsonSchemaToType" packages/worker/src/mcp/capabilities/ -A 5 -B 2Repository: kentcdodds/kody
Length of output: 6354
🏁 Script executed:
rg -l "objectSchemaToType" packages/worker/src/mcp/capabilities/ --type ts | xargs grep -l "test\|spec" 2>/dev/null || echo "No test files found for objectSchemaToType"Repository: kentcdodds/kody
Length of output: 123
🏁 Script executed:
fd "schema-type-definitions" packages/worker/ --type fRepository: kentcdodds/kody
Length of output: 123
🏁 Script executed:
rg "schema-type-definitions" packages/worker/ --type ts -lRepository: kentcdodds/kody
Length of output: 117
🏁 Script executed:
cat -n packages/worker/src/mcp/capabilities/define-capability.ts | head -200Repository: kentcdodds/kody
Length of output: 7056
🏁 Script executed:
rg "additionalProperties" packages/worker/src/mcp/capabilities/schema-type-definitions.ts -nRepository: kentcdodds/kody
Length of output: 434
Prevent index signatures alongside named properties that violate TypeScript's index signature contract.
When named properties exist, line 120 produces invalid TypeScript type declarations. For example, {foo: string, [key: string]: number} fails type checking because the property foo must satisfy the index signature type.
Proposed fix
- if (isRecord(additionalProperties)) {
+ if (isRecord(additionalProperties) && propertyEntries.length === 0) {
lines.push(`\t[key: string]: ${jsonSchemaToType(additionalProperties)}`)
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/worker/src/mcp/capabilities/schema-type-definitions.ts` around lines
119 - 121, The index-signature emission currently unconditionally pushes an
index signature when additionalProperties is a record, which can conflict with
previously emitted named properties; change the logic in the block that calls
isRecord(additionalProperties) and lines.push(...) so you only emit the index
signature if there are no named property lines already emitted (i.e., detect
existing named properties in the lines array before pushing), or alternatively
widen the index signature type to include the union of named property types; use
the existing identifiers additionalProperties, isRecord, lines and
jsonSchemaToType to locate and modify the code that creates the index signature.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b26cf5b. Configure here.
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.ts (1)
150-205: Consider extracting the repeatedHOME_CONNECTOR_SESSIONmock setup into a helper.Both tests construct nearly identical env stubs; a helper would reduce drift and make future updates easier.
♻️ Optional refactor sketch
+function createHomeConnectorEnv(tools = runtimeHomeTools): Env { + return { + HOME_CONNECTOR_SESSION: { + idFromName(name: string) { + return name + }, + get() { + return { + fetch() { + return Promise.resolve( + Response.json({ + connectorId: 'default', + connectedAt: '2026-03-25T00:00:00.000Z', + lastSeenAt: '2026-03-25T00:00:01.000Z', + tools, + }), + ) + }, + } + }, + }, + } as unknown as Env +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.ts` around lines 150 - 205, Extract the repeated HOME_CONNECTOR_SESSION mock into a shared test helper (e.g., makeHomeConnectorEnv or buildHomeConnectorEnv) that returns the env stub typed as Env with the idFromName/get/fetch behavior and runtimeHomeTools wiring; replace the inline env construction in meta_list_capabilities test (and other tests using the same stub) by calling this helper and pass the resulting env into metaListCapabilitiesCapability.handler so tests remain identical but DRYer and easier to update.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@packages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.ts`:
- Around line 150-205: Extract the repeated HOME_CONNECTOR_SESSION mock into a
shared test helper (e.g., makeHomeConnectorEnv or buildHomeConnectorEnv) that
returns the env stub typed as Env with the idFromName/get/fetch behavior and
runtimeHomeTools wiring; replace the inline env construction in
meta_list_capabilities test (and other tests using the same stub) by calling
this helper and pass the resulting env into
metaListCapabilitiesCapability.handler so tests remain identical but DRYer and
easier to update.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 237257ef-6a9e-47b6-9d10-7c1f1ff9ce15
📒 Files selected for processing (8)
docs/use/search.mdpackages/worker/src/mcp/capabilities/capability-search.tspackages/worker/src/mcp/capabilities/capability-search.workers.test.tspackages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.tspackages/worker/src/mcp/capabilities/meta/meta-list-capabilities.tspackages/worker/src/mcp/tools/search-format.node.test.tspackages/worker/src/mcp/tools/search-format.tspackages/worker/src/mcp/tools/search.ts
✅ Files skipped from review due to trivial changes (1)
- docs/use/search.md
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/worker/src/mcp/tools/search-format.node.test.ts
- packages/worker/src/mcp/capabilities/capability-search.workers.test.ts
- packages/worker/src/mcp/tools/search-format.ts
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>

Summary
includeSchemas: trueto receiveinputSchema/outputSchemaalongside type definitions.allOfcomposes TypeScript intersections.allOfprecedence behavior with focused tests.Testing
npm exec vitest run packages/worker/src/mcp/capabilities/schema-type-definitions.node.test.ts packages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.ts packages/worker/src/mcp/tools/search-format.node.test.ts packages/worker/src/mcp/capabilities/capability-search.workers.test.tsnpm run typechecknpm run lintnpx oxfmt --check packages/worker/src/mcp/capabilities/schema-type-definitions.ts packages/worker/src/mcp/capabilities/schema-type-definitions.node.test.ts packages/worker/src/mcp/capabilities/meta/meta-list-capabilities.node.test.tsnpm run buildnpm run testNotes
npm run format:checkstill reports unrelated existing formatting drift outside this change set.Summary by CodeRabbit
New Features
Documentation