Skip to content

Conversation

@betterclever
Copy link
Contributor

@betterclever betterclever commented Jan 15, 2026

Summary

Adds tool mode metadata for agent-callable components, allowing components to be exposed as MCP tools.

Changes

✨ Features

  • Add `agentTool` configuration to component UI metadata
  • Add `ToolMetadata` and `ToolInputSchema` types for MCP compatibility
  • Add helper functions:
    • `isAgentCallable()` - check if a component is configured as an agent-callable tool
    • `inferBindingType()` - infer credential vs action input binding
    • `getCredentialInputIds()` / `getActionInputIds()` - filter inputs by binding type
    • `getToolSchema()` - generate JSON Schema for action inputs only
    • `getToolName()` / `getToolDescription()` - get tool metadata
    • `getToolMetadata()` - get complete MCP-compatible tool metadata

🐛 Bug Fixes

  • Fixed P2 bug: `json`/`any` ports were incorrectly forced to `type: 'object'` in MCP tool schemas
    • Now uses Zod's built-in `toJSONSchema()` for accurate type conversion:
      • `z.any()` → `{}` (empty schema = any JSON value) ✅
      • `z.union([...])` → `{ anyOf: [...] }` ✅
      • `z.enum([...])` → `{ type: 'string', enum: [...] }` ✅
      • `z.literal('X')` → `{ type: 'string', const: 'X' }` ✅
      • `z.record(...)` → `{ type: 'object', additionalProperties: {...} }` ✅

🏗️ Refactoring

  • Uses official `@modelcontextprotocol/sdk` types for `Tool` and `ToolInputSchema`
  • Simplified `tool-helpers.ts` by removing redundant helper functions
  • Reuses existing `getActionInputIds()` function instead of duplicating logic

Testing

All component-sdk tests pass:
```
126 pass
7 skip
0 fail
```

Type Definitions

```typescript
import type { Tool } from '@modelcontextprotocol/sdk/types.js';

// Uses MCP SDK's official Tool.inputSchema type
export type ToolInputSchema = Tool['inputSchema'];

export interface ToolMetadata {
name: string;
description: string;
inputSchema: ToolInputSchema;
}
```

@betterclever betterclever force-pushed the eng-95/component-sdk-tool-mode branch from 13abde0 to 7e4d294 Compare January 15, 2026 16:39
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e4d294d12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 106 to 108
case 'json':
case 'any':
return 'object';

Choose a reason for hiding this comment

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

P2 Badge Do not force json/any ports to object in tool schema

portTypeToJsonSchemaType maps both json and any to the JSON Schema type object, but coercePrimitive in ports.ts accepts any value for these port types (strings, numbers, arrays, etc.). This makes the generated MCP inputSchema reject legitimate non-object inputs (e.g., a JSON array or string) or mislead agents about the expected shape. Consider omitting type for these ports or using a permissive schema so tool calls that pass valid non-object JSON aren’t rejected.

Useful? React with 👍 / 👎.

@betterclever betterclever force-pushed the eng-95/component-sdk-tool-mode branch 2 times, most recently from 4f4cee6 to f09bb4d Compare January 19, 2026 13:00
betterclever added a commit that referenced this pull request Jan 20, 2026
…emas

Previously, json/any ports were incorrectly forced to type: 'object' in
MCP tool schemas. This fix uses Zod's built-in toJSONSchema() method
which correctly handles all types:

- z.any() → {} (empty schema = any JSON value)
- z.union([...]) → { anyOf: [...] }
- z.enum([...]) → { type: 'string', enum: [...] }
- z.literal('X') → { type: 'string', const: 'X' }
- z.record(...) → { type: 'object', additionalProperties: {...} }

This also simplifies the code by removing redundant helper functions
and reusing the existing getActionInputIds() function.

Fixes P2 bug in PR #207

Signed-off-by: betterclever <paliwal.pranjal83@gmail.com>
@betterclever betterclever force-pushed the eng-95/component-sdk-tool-mode branch from f09bb4d to 96df26b Compare January 20, 2026 11:31
betterclever added a commit that referenced this pull request Jan 20, 2026
Previously, json/any ports were incorrectly forced to type: 'object' in
MCP tool schemas. This fix uses Zod's built-in toJSONSchema() method
which correctly handles all types:

- z.any() → {} (empty schema = any JSON value)
- z.union([...]) → { anyOf: [...] }
- z.enum([...]) → { type: 'string', enum: [...] }
- z.literal('X') → { type: 'string', const: 'X' }
- z.record(...) → { type: 'object', additionalProperties: {...} }

Changes:
- Use @modelcontextprotocol/sdk for official Tool types
- ToolInputSchema now derives from Tool['inputSchema']
- Simplified code by reusing existing getActionInputIds()
- Removed redundant helper functions

Fixes P2 bug in PR #207

Signed-off-by: betterclever <paliwal.pranjal83@gmail.com>
@betterclever betterclever force-pushed the eng-95/component-sdk-tool-mode branch from 96df26b to f3da236 Compare January 20, 2026 11:45
…ents

ENG-95

- Add PortBindingType and bindingType to ComponentPortMetadata
- Add AgentToolConfig and agentTool to ComponentUiMetadata
- Create tool-helpers.ts with isAgentCallable, getToolSchema, getCredentialInputIds, getActionInputIds, getToolName, getToolDescription, getToolMetadata
- Add comprehensive tests for all helper functions (14 tests)

Signed-off-by: betterclever <paliwal.pranjal83@gmail.com>
…itecture

Signed-off-by: betterclever <paliwal.pranjal83@gmail.com>
Previously, json/any ports were incorrectly forced to type: 'object' in
MCP tool schemas. This fix uses Zod's built-in toJSONSchema() method
which correctly handles all types:

- z.any() → {} (empty schema = any JSON value)
- z.union([...]) → { anyOf: [...] }
- z.enum([...]) → { type: 'string', enum: [...] }
- z.literal('X') → { type: 'string', const: 'X' }
- z.record(...) → { type: 'object', additionalProperties: {...} }

Changes:
- Use @modelcontextprotocol/sdk for official Tool types
- ToolInputSchema now derives from Tool['inputSchema']
- Simplified code by reusing existing getActionInputIds()
- Removed redundant helper functions

Fixes P2 bug in PR #207

Signed-off-by: betterclever <paliwal.pranjal83@gmail.com>
@betterclever betterclever force-pushed the eng-95/component-sdk-tool-mode branch from f3da236 to 0660362 Compare January 20, 2026 11:46
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.

2 participants