Skip to main content
Glama
Catter58

mcpBPMSoft

by Catter58

Поиск поля по подписи

bpm_find_field
Read-onlyIdempotent

Search for fields by name fragment in loaded schemas, even if you only know a partial name like 'INN' or 'City'.

Instructions

Находит поля по фрагменту русского/английского названия среди уже загруженных схем коллекций. Полезно когда пользователь оперирует «ИНН», «Город» и т.п.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
searchYesТекст для поиска по русскому или английскому названию
collectionNoКоллекция для поиска (если опущена — по уже загруженным схемам)

Implementation Reference

  • 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,
          };
        }
      }
    );
  • 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',
    },
  • 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;
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, destructiveHint, idempotentHint, and openWorldHint, covering safety and behavior. The description adds that it searches among 'already loaded schemas', which is a useful contextual detail, but does not elaborate on edge cases like empty results or performance. With strong annotations, this is sufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with two sentences. The first sentence states the core action and scope, and the second provides a practical use case. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simplicity of the tool (two parameters, no output schema, clear annotations), the description covers the essential context. It explains what the tool does and when to use it. The only minor omission is what exactly is returned, but that is implicitly understood from the purpose.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already describes both parameters completely (100% coverage). The description adds no additional semantic information beyond what the schema provides, so the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool finds fields by a fragment of their Russian/English name among already loaded collection schemas. The example with 'ИНН' and 'Город' reinforces the purpose. This tool is distinct from sibling tools, which focus on records, batch operations, or processes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear use case (when the user is dealing with terms like 'ИНН', 'Город') but does not explicitly state when not to use it or mention alternatives. However, given the tool's focused purpose and lack of similar siblings, the guidance is adequate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Catter58/mcpBPMSoft'

If you have feedback or need assistance with the MCP directory API, please join our Discord server