Поиск поля по подписи
bpm_find_fieldSearch for fields by name fragment in loaded schemas, even if you only know a partial name like 'INN' or 'City'.
Instructions
Находит поля по фрагменту русского/английского названия среди уже загруженных схем коллекций. Полезно когда пользователь оперирует «ИНН», «Город» и т.п.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| search | Yes | Текст для поиска по русскому или английскому названию | |
| collection | No | Коллекция для поиска (если опущена — по уже загруженным схемам) |
Implementation Reference
- src/tools/schema-tools.ts:241-299 (handler)Handler function that registers the bpm_find_field tool. Takes 'search' (required text to search by RU/EN name) and 'collection' (optional, to scope search). Calls metadataManager.findFieldByCaption() and formats results.
const meta = getTool('bpm_find_field'); server.registerTool( meta.name, { title: meta.title, description: meta.description, inputSchema: { search: z.string().describe('Текст для поиска по русскому или английскому названию'), collection: z.string().optional().describe('Коллекция для поиска (если опущена — по уже загруженным схемам)'), }, annotations: meta.annotations, }, async (params): Promise<CallToolResult> => { if (!services.initialized) return notInitialized(); try { await services.authManager.ensureAuthenticated(); if (params.collection) { await services.metadataManager.getEntityMetadata(params.collection); } const results = await services.metadataManager.findFieldByCaption(params.search, params.collection); if (results.length === 0) { return { content: [ { type: 'text', text: params.collection ? `Поле "${params.search}" не найдено в коллекции ${params.collection}.\nУбедитесь, что схема загружена (bpm_get_schema).` : `Поле "${params.search}" не найдено.\nСначала загрузите нужные схемы через bpm_get_schema.`, }, ], structuredContent: { count: 0, results: [] }, }; } const lines = [`Найдено полей по запросу "${params.search}": ${results.length}`, '']; for (const r of results) { const captionPart = r.caption ? ` [${r.caption}]` : ''; const lookupPart = r.isLookup ? ' (lookup)' : ''; lines.push(` ${r.collection}.${r.fieldName}${captionPart}: ${r.type}${lookupPart}`); } lines.push(''); lines.push('Используйте английское имя поля (fieldName) в OData-запросах.'); return { content: [{ type: 'text', text: lines.join('\n') }], structuredContent: { count: results.length, results }, }; } catch (error) { const toolError = formatToolError(error); return { content: [{ type: 'text', text: JSON.stringify(toolError, null, 2) }], isError: true, }; } } ); - src/tools/registry.ts:167-175 (schema)Tool metadata registration: name, title, description, annotations (read-only, idempotent, open-world), and category 'schema'.
{ name: 'bpm_find_field', title: 'Поиск поля по подписи', description: 'Находит поля по фрагменту русского/английского названия среди уже загруженных схем коллекций. Полезно когда пользователь оперирует «ИНН», «Город» и т.п.', annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, blurb: 'поиск поля по подписи (RU/EN)', category: 'schema', }, - src/tools/schema-tools.ts:241-299 (registration)Registration call using server.registerTool with meta.name from the registry. InputSchema defines 'search' (string, required) and 'collection' (string, optional).
const meta = getTool('bpm_find_field'); server.registerTool( meta.name, { title: meta.title, description: meta.description, inputSchema: { search: z.string().describe('Текст для поиска по русскому или английскому названию'), collection: z.string().optional().describe('Коллекция для поиска (если опущена — по уже загруженным схемам)'), }, annotations: meta.annotations, }, async (params): Promise<CallToolResult> => { if (!services.initialized) return notInitialized(); try { await services.authManager.ensureAuthenticated(); if (params.collection) { await services.metadataManager.getEntityMetadata(params.collection); } const results = await services.metadataManager.findFieldByCaption(params.search, params.collection); if (results.length === 0) { return { content: [ { type: 'text', text: params.collection ? `Поле "${params.search}" не найдено в коллекции ${params.collection}.\nУбедитесь, что схема загружена (bpm_get_schema).` : `Поле "${params.search}" не найдено.\nСначала загрузите нужные схемы через bpm_get_schema.`, }, ], structuredContent: { count: 0, results: [] }, }; } const lines = [`Найдено полей по запросу "${params.search}": ${results.length}`, '']; for (const r of results) { const captionPart = r.caption ? ` [${r.caption}]` : ''; const lookupPart = r.isLookup ? ' (lookup)' : ''; lines.push(` ${r.collection}.${r.fieldName}${captionPart}: ${r.type}${lookupPart}`); } lines.push(''); lines.push('Используйте английское имя поля (fieldName) в OData-запросах.'); return { content: [{ type: 'text', text: lines.join('\n') }], structuredContent: { count: results.length, results }, }; } catch (error) { const toolError = formatToolError(error); return { content: [{ type: 'text', text: JSON.stringify(toolError, null, 2) }], isError: true, }; } } ); - Core search logic: iterates over cached entity metadata properties, matching by case-insensitive substring on caption or field name. If a collection is specified, searches only that collection; otherwise searches all cached schemas.
async findFieldByCaption( searchText: string, collection?: string ): Promise<Array<{ collection: string; fieldName: string; caption: string; type: string; isLookup: boolean }>> { const results: Array<{ collection: string; fieldName: string; caption: string; type: string; isLookup: boolean }> = []; const lowerSearch = searchText.toLowerCase(); const collectFromMetadata = (metadata: EntityMetadata) => { for (const prop of metadata.properties) { const caption = prop.caption || ''; if (caption.toLowerCase().includes(lowerSearch) || prop.name.toLowerCase().includes(lowerSearch)) { results.push({ collection: metadata.collectionName, fieldName: prop.name, caption, type: prop.type, isLookup: prop.isLookup, }); } } }; if (collection) { const metadata = await this.getEntityMetadata(collection); collectFromMetadata(metadata); } else { for (const [, metadata] of this.cache) collectFromMetadata(metadata); } return results; }