import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { JsmClient } from '../api/jsmClient.js';
import { validateObjectTypeId, formatError, logDebug } from '../utils/index.js';
export const getObjectAttributesTool: Tool = {
name: 'get_object_attributes',
description: 'Get all attributes (fields) for a specific object type. Attributes define what data can be stored for objects of this type.',
inputSchema: {
type: 'object',
properties: {
objectTypeId: {
type: 'number',
description: 'The ID of the object type to get attributes for'
}
},
required: ['objectTypeId']
}
};
export async function handleGetObjectAttributes(
client: JsmClient,
args: any
): Promise<{ content: Array<{ type: string; text: string }> }> {
try {
const { objectTypeId } = args;
validateObjectTypeId(objectTypeId);
logDebug('Fetching object attributes', { objectTypeId });
const result = await client.getObjectAttributes(objectTypeId);
logDebug('Object attributes fetched', {
count: result?.length,
objectTypeId
});
const summary = `Found ${result?.length || 0} attributes for object type ${objectTypeId}`;
let formattedResults = '';
if (result && result.length > 0) {
const sortedAttributes = result.sort((a, b) => a.position - b.position);
formattedResults = sortedAttributes.map((attr, index) => {
const typeInfo = getAttributeTypeInfo(attr.type, attr.defaultTypeId);
const systemInfo = attr.system ? ' [System]' : '';
const requiredInfo = attr.minimumCardinality > 0 ? ' [Required]' : '';
const uniqueInfo = attr.uniqueAttribute ? ' [Unique]' : '';
const editableInfo = !attr.editable ? ' [Read-only]' : '';
const hiddenInfo = attr.hidden ? ' [Hidden]' : '';
const referenceInfo = attr.referenceObjectTypeId ?
`\n References: Object Type ${attr.referenceObjectTypeId}` : '';
return `${index + 1}. ${attr.label} (${attr.name})${systemInfo}${requiredInfo}${uniqueInfo}${editableInfo}${hiddenInfo}
Type: ${typeInfo}
Cardinality: ${attr.minimumCardinality}-${attr.maximumCardinality === -1 ? '∞' : attr.maximumCardinality}
Position: ${attr.position}${referenceInfo}
Sortable: ${attr.sortable ? 'Yes' : 'No'} | Indexed: ${attr.indexed ? 'Yes' : 'No'}`;
}).join('\n\n');
}
return {
content: [
{
type: 'text',
text: `${summary}\n\n${formattedResults}`
}
]
};
} catch (error) {
logDebug('Get object attributes error', error);
return {
content: [
{
type: 'text',
text: `Error getting object attributes: ${formatError(error)}`
}
]
};
}
}
function getAttributeTypeInfo(type: number, defaultTypeId: number): string {
const typeMap: { [key: number]: string } = {
0: 'Default',
1: 'Text',
2: 'Integer',
3: 'Boolean',
4: 'Double',
5: 'Date',
6: 'Time',
7: 'Date Time',
8: 'URL',
9: 'Email',
10: 'Textarea',
11: 'Select',
12: 'IP Address',
13: 'Reference',
14: 'User',
15: 'Group',
16: 'Version',
17: 'Project',
18: 'Status'
};
const typeName = typeMap[type] || `Unknown (${type})`;
const defaultTypeName = defaultTypeId !== type ? ` (Default: ${typeMap[defaultTypeId] || defaultTypeId})` : '';
return `${typeName}${defaultTypeName}`;
}