Skip to main content
Glama
antegral

MMA MCP Server

by antegral

search_designated_entities

Search for South Korean companies designated for military service alternatives like industrial technicians, research specialists, or naval reservists. Filter by service type, industry, location, and company size to find eligible employers.

Instructions

병무청 병역일터에서 병역특례 지정업체를 검색합니다. 산업기능요원, 전문연구요원, 승선근무예비역 복무가 가능한 업체 정보를 조회할 수 있습니다. 검색 결과는 CSV 형식으로 반환되며, 최대 30개의 업체 정보가 제공됩니다.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
service_typeYes(필수) 복무 형태를 선택합니다.
company_sizeNo기업 규모 (선택사항, 빈 값은 전체 조회)
industry_sectorsNo업종 코드 (선택사항, 여러 개 가능)
company_nameNo회사 이름 (선택사항, 빈 값은 전체 조회)
city_provinceNo시/도 선택 (선택사항, 빈 값은 전국 전체 조회)
city_districtNo시/군/구 주소 (선택사항, 빈 값은 city_province 전체 조회)
is_hiringNo병무청 채용 공고 등록 업체 여부 (선택사항, 'Y' 또는 빈 값)
military_service_statusNo현역 또는 보충역 TO 유무 (전체 조회시 H, B 모두 입력)

Implementation Reference

  • Core implementation of the `search_designated_entities` tool: builds form data, sends POST request to MMA API, parses XLS response to CSV using XLSX library, limits to 30 rows, filters empty rows, returns CSV string.
    export async function search_designated_entities(
      query: MilitaryWorkplaceSearchQuery,
    ): Promise<string> {
      // Form data 생성
      const formData = buildFormData(query);
    
      // HTTP 요청
      const response = await fetch(MMA_API_ENDPOINT, {
        method: 'POST',
        headers: {
          accept:
            'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
          'accept-language': 'ko,en-US;q=0.9,en;q=0.8',
          'cache-control': 'no-cache',
          'content-type': 'application/x-www-form-urlencoded',
          Referer: 'https://work.mma.go.kr/caisBYIS/search/byjjecgeomsaek.do',
        },
        body: formData,
      })
        .then((response) => {
          return response;
        })
        .catch((error) => {
          console.error(`error: ${error}`);
          throw new MMAApiError(`MMA API request failed: ${error.message}`, error.status);
        });
    
      // 응답을 ArrayBuffer로 받아서 처리
      const arrayBuffer = await response.arrayBuffer();
      const workbook = XLSX.read(arrayBuffer, { type: 'array' });
    
      // 첫 번째 시트 가져오기
      const firstSheetName = workbook.SheetNames[0];
      if (!firstSheetName) {
        throw new MMAApiError('No worksheet found in the response');
      }
    
      const worksheet = workbook.Sheets[firstSheetName];
    
      // .xls -> .csv 형태로 변환
      const strData = XLSX.utils.sheet_to_csv(worksheet, { FS: ',', RS: '\n' });
    
      // \n으로 split하여 Array를 얻고, Header (row 0)를 제외한 나머지 부분을 slice
      // 최대 30개의 row만 리턴 (헤더 제외)
      const rows = strData.split('\n');
      const dataRows = rows.slice(1, 31); // 헤더 제외, 최대 30개
    
      // 빈 행 필터링
      const filteredRows = dataRows.filter((row) => row.trim() !== '');
    
      if (filteredRows.length === 0) {
        return 'No data found for the given search criteria.';
      }
    
      // 헤더와 데이터를 함께 반환
      const header = rows[0];
      return `${header}\n${filteredRows.join('\n')}`;
    }
  • JSON schema defining the input parameters for the tool, including enums for service types, company sizes, industries, locations, and supports arrays for multi-select fields like industries and military statuses.
    inputSchema: {
      type: 'object',
      properties: {
        service_type: {
          type: 'string',
          enum: ['산업기능요원', '전문연구요원', '승선근무예비역'],
          description: '(필수) 복무 형태를 선택합니다.',
        },
        company_size: {
          type: 'string',
          enum: ['', '대기업', '중소기업', '중견기업', '농어민후계', '기타'],
          description: '기업 규모 (선택사항, 빈 값은 전체 조회)',
        },
        industry_sectors: {
          oneOf: [
            {
              type: 'string',
              enum: [
                '철강',
                '기계',
                '전기',
                '전자',
                '화학',
                '섬유',
                '신발',
                '시멘요업',
                '생활용품',
                '통신기기',
                '정보처리',
                '게임SW',
                '영상게임',
                '의료의약',
                '식음료',
                '농산물가공',
                '수산물가공',
                '임산물가공',
                '동물약품',
                '애니메이션',
                '석탄채굴',
                '일반광물채굴',
                '선광제련',
                '에너지',
                '국내건설',
                '국외건설',
                '내항화물',
                '외항화물',
                '내항선박관리',
                '외항선박관리',
                '근해',
                '원양',
              ],
            },
            {
              type: 'array',
              items: {
                type: 'string',
                enum: [
                  '철강',
                  '기계',
                  '전기',
                  '전자',
                  '화학',
                  '섬유',
                  '신발',
                  '시멘요업',
                  '생활용품',
                  '통신기기',
                  '정보처리',
                  '게임SW',
                  '영상게임',
                  '의료의약',
                  '식음료',
                  '농산물가공',
                  '수산물가공',
                  '임산물가공',
                  '동물약품',
                  '애니메이션',
                  '석탄채굴',
                  '일반광물채굴',
                  '선광제련',
                  '에너지',
                  '국내건설',
                  '국외건설',
                  '내항화물',
                  '외항화물',
                  '내항선박관리',
                  '외항선박관리',
                  '근해',
                  '원양',
                ],
              },
            },
          ],
          description: '업종 코드 (선택사항, 여러 개 가능)',
        },
        company_name: {
          type: 'string',
          description: '회사 이름 (선택사항, 빈 값은 전체 조회)',
        },
        city_province: {
          type: 'string',
          enum: [
            '서울특별시',
            '부산광역시',
            '대구광역시',
            '인천광역시',
            '광주광역시',
            '대전광역시',
            '울산광역시',
            '세종특별자치시',
            '경기도',
            '충청북도',
            '충청남도',
            '전라남도',
            '경상북도',
            '경상남도',
            '제주특별자치도',
            '강원특별자치도',
            '전북특별자치도',
          ],
          description: '시/도 선택 (선택사항, 빈 값은 전국 전체 조회)',
        },
        city_district: {
          type: 'string',
          description: '시/군/구 주소 (선택사항, 빈 값은 city_province 전체 조회)',
        },
        is_hiring: {
          type: 'boolean',
          enum: [true, false],
          description: "병무청 채용 공고 등록 업체 여부 (선택사항, 'Y' 또는 빈 값)",
        },
        military_service_status: {
          oneOf: [
            {
              type: 'string',
              enum: ['현역', '보충역'],
            },
            {
              type: 'array',
              items: {
                type: 'string',
                enum: ['현역', '보충역'],
              },
            },
          ],
          description: '현역 또는 보충역 TO 유무 (전체 조회시 H, B 모두 입력)',
        },
      },
      required: ['service_type'],
    },
  • src/index.ts:21-179 (registration)
    Registration of the tool in the TOOLS array, including name, detailed Korean description, and reference to inputSchema. Used in ListToolsRequestHandler.
    const TOOLS: Tool[] = [
      {
        name: 'search_designated_entities',
        description:
          '병무청 병역일터에서 병역특례 지정업체를 검색합니다. ' +
          '산업기능요원, 전문연구요원, 승선근무예비역 복무가 가능한 업체 정보를 조회할 수 있습니다. ' +
          '검색 결과는 CSV 형식으로 반환되며, 최대 30개의 업체 정보가 제공됩니다.',
        inputSchema: {
          type: 'object',
          properties: {
            service_type: {
              type: 'string',
              enum: ['산업기능요원', '전문연구요원', '승선근무예비역'],
              description: '(필수) 복무 형태를 선택합니다.',
            },
            company_size: {
              type: 'string',
              enum: ['', '대기업', '중소기업', '중견기업', '농어민후계', '기타'],
              description: '기업 규모 (선택사항, 빈 값은 전체 조회)',
            },
            industry_sectors: {
              oneOf: [
                {
                  type: 'string',
                  enum: [
                    '철강',
                    '기계',
                    '전기',
                    '전자',
                    '화학',
                    '섬유',
                    '신발',
                    '시멘요업',
                    '생활용품',
                    '통신기기',
                    '정보처리',
                    '게임SW',
                    '영상게임',
                    '의료의약',
                    '식음료',
                    '농산물가공',
                    '수산물가공',
                    '임산물가공',
                    '동물약품',
                    '애니메이션',
                    '석탄채굴',
                    '일반광물채굴',
                    '선광제련',
                    '에너지',
                    '국내건설',
                    '국외건설',
                    '내항화물',
                    '외항화물',
                    '내항선박관리',
                    '외항선박관리',
                    '근해',
                    '원양',
                  ],
                },
                {
                  type: 'array',
                  items: {
                    type: 'string',
                    enum: [
                      '철강',
                      '기계',
                      '전기',
                      '전자',
                      '화학',
                      '섬유',
                      '신발',
                      '시멘요업',
                      '생활용품',
                      '통신기기',
                      '정보처리',
                      '게임SW',
                      '영상게임',
                      '의료의약',
                      '식음료',
                      '농산물가공',
                      '수산물가공',
                      '임산물가공',
                      '동물약품',
                      '애니메이션',
                      '석탄채굴',
                      '일반광물채굴',
                      '선광제련',
                      '에너지',
                      '국내건설',
                      '국외건설',
                      '내항화물',
                      '외항화물',
                      '내항선박관리',
                      '외항선박관리',
                      '근해',
                      '원양',
                    ],
                  },
                },
              ],
              description: '업종 코드 (선택사항, 여러 개 가능)',
            },
            company_name: {
              type: 'string',
              description: '회사 이름 (선택사항, 빈 값은 전체 조회)',
            },
            city_province: {
              type: 'string',
              enum: [
                '서울특별시',
                '부산광역시',
                '대구광역시',
                '인천광역시',
                '광주광역시',
                '대전광역시',
                '울산광역시',
                '세종특별자치시',
                '경기도',
                '충청북도',
                '충청남도',
                '전라남도',
                '경상북도',
                '경상남도',
                '제주특별자치도',
                '강원특별자치도',
                '전북특별자치도',
              ],
              description: '시/도 선택 (선택사항, 빈 값은 전국 전체 조회)',
            },
            city_district: {
              type: 'string',
              description: '시/군/구 주소 (선택사항, 빈 값은 city_province 전체 조회)',
            },
            is_hiring: {
              type: 'boolean',
              enum: [true, false],
              description: "병무청 채용 공고 등록 업체 여부 (선택사항, 'Y' 또는 빈 값)",
            },
            military_service_status: {
              oneOf: [
                {
                  type: 'string',
                  enum: ['현역', '보충역'],
                },
                {
                  type: 'array',
                  items: {
                    type: 'string',
                    enum: ['현역', '보충역'],
                  },
                },
              ],
              description: '현역 또는 보충역 TO 유무 (전체 조회시 H, B 모두 입력)',
            },
          },
          required: ['service_type'],
        },
      },
    ];
  • MCP CallToolRequestHandler switch case that maps user input arguments to MilitaryWorkplaceSearchQuery, validates required fields, calls the core search_designated_entities function, and formats the CSV result as MCP tool response.
    case 'search_designated_entities': {
      if (!query.eopjong_gbcd) {
        throw new Error('eopjong_gbcd parameter is required');
      }
    
      const result = await search_designated_entities(query);
    
      return {
        content: [
          {
            type: 'text',
            text: result,
          },
        ],
      };
    }
  • Helper function to convert MilitaryWorkplaceSearchQuery into URLSearchParams form data for the MMA API POST request, handling enum mappings and multi-value fields.
    export function buildFormData(query: MilitaryWorkplaceSearchQuery): string {
      const params = new URLSearchParams();
    
      // 필수 필드: eopjong_gbcd (복무 형태)
      const agentTypeValue = AgentType[query.eopjong_gbcd];
      params.append('eopjong_gbcd', agentTypeValue);
    
      // al_eopjong_gbcd_yn: 빈 문자열로 설정
      params.append('al_eopjong_gbcd_yn', '');
    
      // gegyumo_cd: 기업 규모
      if (query.gegyumo_cd !== undefined && query.gegyumo_cd !== '') {
        const sizeCode = CompanySizeCode[query.gegyumo_cd];
        if (sizeCode) {
          params.append('gegyumo_cd', sizeCode);
        }
      } else if (query.gegyumo_cd === '') {
        params.append('gegyumo_cd', '');
      }
    
      // eopjong_cd: 업종 코드 (여러 개 가능)
      if (query.eopjong_cd) {
        const codes = Array.isArray(query.eopjong_cd) ? query.eopjong_cd : [query.eopjong_cd];
        codes.forEach((industry) => {
          const code = IndustryCode[industry];
          if (code) {
            params.append('eopjong_cd', code);
          }
        });
    
        // e.g) 11111,11112 (and no encoding)
        const codeValues = codes.map((industry) => IndustryCode[industry]).filter(Boolean);
        const al_eopjong_gbcd = codeValues.join(',');
        const eopjong_gbcd_list = codeValues.join(','); // al_eopjong_gbcd와 동일
    
        if (al_eopjong_gbcd) {
          params.append('al_eopjong_gbcd', al_eopjong_gbcd);
        }
    
        if (eopjong_gbcd_list) {
          params.append('eopjong_gbcd_list', eopjong_gbcd_list);
        }
      }
    
      // eopche_nm: 회사 이름
      if (query.eopche_nm !== undefined) {
        params.append('eopche_nm', query.eopche_nm);
      }
    
      // sido_addr: 시/도
      if (query.sido_addr) {
        params.append('sido_addr', query.sido_addr);
      }
    
      // sigungu_addr: 시/군/구
      if (query.sigungu_addr !== undefined) {
        params.append('sigungu_addr', query.sigungu_addr);
      }
    
      // chaeyongym: 채용 공고 등록 업체
      if (query.chaeyongym !== undefined) {
        params.append('chaeyongym', query.chaeyongym);
      }
    
      // bjinwonym: 현역/보충역 TO 유무 (여러 개 가능)
      if (query.bjinwonym) {
        const values = Array.isArray(query.bjinwonym) ? query.bjinwonym : [query.bjinwonym];
        values.forEach((value) => {
          params.append('bjinwonym', value);
        });
      }
    
      return params.toString();
    }
Behavior4/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes key behavioral traits: it specifies the output format (CSV), result limit (maximum 30 companies), and that it's a read-only search operation (implied by '검색합니다' and '조회할 수 있습니다'). However, it doesn't mention potential rate limits, authentication requirements, or error conditions.

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

Conciseness4/5

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

The description is appropriately concise with three sentences that each serve a clear purpose: stating the tool's function, specifying the types of companies searched, and describing output format and limits. It's front-loaded with the core functionality, though the second sentence could be slightly more streamlined.

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 tool's moderate complexity (8 parameters, no output schema, no annotations), the description provides good contextual completeness. It covers the tool's purpose, scope, output format, and result limits. The main gap is the lack of output schema, but the description compensates by specifying CSV format and maximum result count, though it doesn't detail the CSV structure.

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 schema description coverage is 100%, so the schema already documents all 8 parameters thoroughly with descriptions and enums. The description doesn't add any parameter-specific information beyond what's in the schema, maintaining the baseline score of 3 where the schema does the heavy lifting without additional value from the description.

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 the tool's purpose with specific verbs ('검색합니다', '조회할 수 있습니다') and resources ('병역일터', '병역특례 지정업체'), specifying the exact data source and target entities. It distinguishes the tool by mentioning the three specific military service types it supports, making its scope explicit even without siblings.

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

Usage Guidelines3/5

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

The description implies usage context by stating what types of companies can be searched (those supporting specific military service types), but it doesn't provide explicit guidance on when to use this tool versus alternatives. Since no sibling tools are listed, there's no opportunity for comparison, but it lacks information about prerequisites or typical use cases beyond the basic functionality.

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/antegral/agent-for-agent'

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