Skip to main content
Glama
openpharma-org

Asian Financial Filings MCP Server

asia-filings

Access financial filings, statements, and XBRL data from 7,700+ companies in Japan (EDINET) and South Korea (DART) to retrieve, analyze, and search company information.

Instructions

Unified tool for Asian financial filings: access company filings, financial statements, and XBRL data from Japan (EDINET) and South Korea (DART). Provides comprehensive access to financial reports from 7,700+ Asian companies.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
methodYesThe operation to perform: JAPAN (EDINET): - search_japan_companies: Search Japanese companies by name - get_japan_company_by_code: Get company by EDINET code - get_japan_company_filings: Get filing history for Japanese company - get_japan_filing_document: Download specific filing document - get_japan_documents_by_date: Get all filings for a specific date - get_japan_filing_facts: Extract XBRL facts from filing (J-GAAP) - get_japan_dimensional_facts: Get dimensional facts with breakdowns KOREA (DART): - search_korea_companies: Search Korean companies by name - get_korea_company_by_code: Get company by corporate code - get_korea_company_filings: Get filing history for Korean company - get_korea_financial_statements: Get financial statements (XBRL) - get_korea_major_shareholders: Get major shareholder information - get_korea_executive_info: Get executive/officer information - get_korea_dividend_info: Get dividend allocation information - get_korea_dimensional_facts: Get dimensional facts with breakdowns ADVANCED ANALYSIS (Phase 2): - build_fact_table: Build comprehensive fact table around target value with BI summaries - search_facts_by_value: Search for facts within value range (alias for build_fact_table) - time_series_analysis: Analyze financial metrics across multiple periods with growth rates UTILITIES: - filter_filings: Filter filing arrays by criteria
queryNoFor search methods: Company name to search (Japanese, Korean, or English)
edinet_codeNoFor Japan methods: EDINET code (E-number)
corp_codeNoFor Korea methods: Corporate code
document_idNoFor get_japan_filing_document: Document ID from EDINET
document_typeNoFor get_japan_filing_document: Document type (1: submission, 2: PDF, 3: attachments, 4: XBRL)
dateNoFor get_japan_documents_by_date: Date in YYYY-MM-DD format
start_dateNoFor filing methods: Start date in YYYY-MM-DD format
end_dateNoFor filing methods: End date in YYYY-MM-DD format
business_yearNoFor get_korea_financial_statements, get_korea_dividend_info: Business year (YYYY)
report_codeNoFor get_korea_financial_statements: Report code (11011: Annual, 11013: Q1, 11012: Q2, 11014: Q3)
report_typeNoFor get_korea_company_filings: Report type filter
limitNoMaximum number of results to return
filingsNoFor filter_filings: Array of filing objects to filter
filtersNoFor filter_filings: Filter criteria (startDate, endDate, reportType)
search_criteriaNoFor dimensional_facts methods: Search criteria (concept, valueRange, period, hasDimensions)
countryNoFor advanced analysis methods: Country code (JP for Japan, KR for Korea)
company_idNoFor advanced analysis methods: EDINET code (JP) or corp code (KR)
target_valueNoFor build_fact_table/search_facts_by_value: Target value to search around
toleranceNoFor build_fact_table/search_facts_by_value: Tolerance range (±)
optionsNoFor advanced analysis methods: Analysis options (maxRows, showDimensions, sortBy, concept, periods, includeGeography, includeSegments, showGrowthRates)

Implementation Reference

  • Registration of ListToolsRequestHandler defining the schema for the 'asia-filings' tool, including all supported methods, parameters, and descriptions.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: 'asia-filings',
            description: 'Unified tool for Asian financial filings: access company filings, financial statements, and XBRL data from Japan (EDINET) and South Korea (DART). Provides comprehensive access to financial reports from 7,700+ Asian companies.',
            inputSchema: {
              type: 'object',
              properties: {
                method: {
                  type: 'string',
                  enum: [
                    // Japan EDINET methods
                    'search_japan_companies',
                    'get_japan_company_by_code',
                    'get_japan_company_filings',
                    'get_japan_filing_document',
                    'get_japan_documents_by_date',
                    'get_japan_filing_facts',
                    'get_japan_dimensional_facts',
                    // Korea DART methods
                    'search_korea_companies',
                    'get_korea_company_by_code',
                    'get_korea_company_filings',
                    'get_korea_financial_statements',
                    'get_korea_major_shareholders',
                    'get_korea_executive_info',
                    'get_korea_dividend_info',
                    'get_korea_dimensional_facts',
                    // Advanced Analysis Methods (Phase 2)
                    'build_fact_table',
                    'search_facts_by_value',
                    'time_series_analysis',
                    // Utility methods
                    'filter_filings'
                  ],
                  description: `The operation to perform:
    
    JAPAN (EDINET):
    - search_japan_companies: Search Japanese companies by name
    - get_japan_company_by_code: Get company by EDINET code
    - get_japan_company_filings: Get filing history for Japanese company
    - get_japan_filing_document: Download specific filing document
    - get_japan_documents_by_date: Get all filings for a specific date
    - get_japan_filing_facts: Extract XBRL facts from filing (J-GAAP)
    - get_japan_dimensional_facts: Get dimensional facts with breakdowns
    
    KOREA (DART):
    - search_korea_companies: Search Korean companies by name
    - get_korea_company_by_code: Get company by corporate code
    - get_korea_company_filings: Get filing history for Korean company
    - get_korea_financial_statements: Get financial statements (XBRL)
    - get_korea_major_shareholders: Get major shareholder information
    - get_korea_executive_info: Get executive/officer information
    - get_korea_dividend_info: Get dividend allocation information
    - get_korea_dimensional_facts: Get dimensional facts with breakdowns
    
    ADVANCED ANALYSIS (Phase 2):
    - build_fact_table: Build comprehensive fact table around target value with BI summaries
    - search_facts_by_value: Search for facts within value range (alias for build_fact_table)
    - time_series_analysis: Analyze financial metrics across multiple periods with growth rates
    
    UTILITIES:
    - filter_filings: Filter filing arrays by criteria`,
                  examples: ['search_japan_companies', 'get_korea_financial_statements']
                },
                query: {
                  type: 'string',
                  description: 'For search methods: Company name to search (Japanese, Korean, or English)',
                  examples: ['Toyota', 'Samsung', 'ソニー', '삼성전자']
                },
                edinet_code: {
                  type: 'string',
                  description: 'For Japan methods: EDINET code (E-number)',
                  examples: ['E01225', 'E02166', 'E05080']
                },
                corp_code: {
                  type: 'string',
                  description: 'For Korea methods: Corporate code',
                  examples: ['00126380', '00164742']
                },
                document_id: {
                  type: 'string',
                  description: 'For get_japan_filing_document: Document ID from EDINET',
                  examples: ['S100XXXX']
                },
                document_type: {
                  type: 'string',
                  description: 'For get_japan_filing_document: Document type (1: submission, 2: PDF, 3: attachments, 4: XBRL)',
                  examples: ['1', '2', '4']
                },
                date: {
                  type: 'string',
                  description: 'For get_japan_documents_by_date: Date in YYYY-MM-DD format',
                  examples: ['2024-12-01', '2024-11-15']
                },
                start_date: {
                  type: 'string',
                  description: 'For filing methods: Start date in YYYY-MM-DD format',
                  examples: ['2023-01-01', '2024-01-01']
                },
                end_date: {
                  type: 'string',
                  description: 'For filing methods: End date in YYYY-MM-DD format',
                  examples: ['2024-12-31', '2024-06-30']
                },
                business_year: {
                  type: 'string',
                  description: 'For get_korea_financial_statements, get_korea_dividend_info: Business year (YYYY)',
                  examples: ['2023', '2024']
                },
                report_code: {
                  type: 'string',
                  description: 'For get_korea_financial_statements: Report code (11011: Annual, 11013: Q1, 11012: Q2, 11014: Q3)',
                  examples: ['11011', '11013']
                },
                report_type: {
                  type: 'string',
                  description: 'For get_korea_company_filings: Report type filter',
                  examples: ['A', 'Q']
                },
                limit: {
                  type: 'integer',
                  description: 'Maximum number of results to return',
                  examples: [10, 25, 50, 100]
                },
                filings: {
                  type: 'array',
                  description: 'For filter_filings: Array of filing objects to filter',
                  items: { type: 'object' }
                },
                filters: {
                  type: 'object',
                  description: 'For filter_filings: Filter criteria (startDate, endDate, reportType)'
                },
                search_criteria: {
                  type: 'object',
                  description: 'For dimensional_facts methods: Search criteria (concept, valueRange, period, hasDimensions)'
                },
                country: {
                  type: 'string',
                  description: 'For advanced analysis methods: Country code (JP for Japan, KR for Korea)',
                  examples: ['JP', 'KR']
                },
                company_id: {
                  type: 'string',
                  description: 'For advanced analysis methods: EDINET code (JP) or corp code (KR)',
                  examples: ['E01225', '00126380']
                },
                target_value: {
                  type: 'number',
                  description: 'For build_fact_table/search_facts_by_value: Target value to search around',
                  examples: [1000000000, 500000000000]
                },
                tolerance: {
                  type: 'number',
                  description: 'For build_fact_table/search_facts_by_value: Tolerance range (±)',
                  examples: [50000000, 100000000]
                },
                options: {
                  type: 'object',
                  description: 'For advanced analysis methods: Analysis options (maxRows, showDimensions, sortBy, concept, periods, includeGeography, includeSegments, showGrowthRates)'
                }
              },
              required: ['method'],
              additionalProperties: false
            }
          }
        ]
      };
    });
  • Main handler for CallTool requests to 'asia-filings', dispatching based on 'method' parameter to specific API implementations in imported modules.
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      if (name !== 'asia-filings') {
        throw new Error(`Unknown tool: ${name}`);
      }
    
      try {
        const { method, ...params } = args;
    
        switch (method) {
          // ============= JAPAN EDINET METHODS =============
    
          case 'search_japan_companies': {
            const { query, limit, date } = params;
            if (!query) {
              throw new Error('query parameter is required for search_japan_companies');
            }
    
            const results = await edinetApi.searchCompanies(query, { limit, date });
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_japan_company_by_code': {
            const { edinet_code } = params;
            if (!edinet_code) {
              throw new Error('edinet_code parameter is required for get_japan_company_by_code');
            }
    
            const result = await edinetApi.getCompanyByEdinetCode(edinet_code);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(result, null, 2)
                }
              ]
            };
          }
    
          case 'get_japan_company_filings': {
            const { edinet_code, start_date, end_date, limit } = params;
            if (!edinet_code) {
              throw new Error('edinet_code parameter is required for get_japan_company_filings');
            }
    
            const results = await edinetApi.getCompanyFilings(edinet_code, {
              startDate: start_date,
              endDate: end_date,
              limit
            });
    
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_japan_filing_document': {
            const { document_id, document_type } = params;
            if (!document_id) {
              throw new Error('document_id parameter is required for get_japan_filing_document');
            }
    
            const result = await edinetApi.getFilingDocument(document_id, document_type || '1');
    
            // For binary data, return metadata only
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify({
                    document_id: result.document_id,
                    type: result.type,
                    content_type: result.content_type,
                    note: 'Document downloaded successfully. Binary data not displayed.'
                  }, null, 2)
                }
              ]
            };
          }
    
          case 'get_japan_documents_by_date': {
            const { date } = params;
            if (!date) {
              throw new Error('date parameter is required for get_japan_documents_by_date');
            }
    
            const results = await edinetApi.getDocumentsByDate(date);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_japan_filing_facts': {
            const { document_id } = params;
            if (!document_id) {
              throw new Error('document_id parameter is required for get_japan_filing_facts');
            }
    
            const results = await edinetApi.getFilingFacts(document_id);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_japan_dimensional_facts': {
            const { document_id, search_criteria } = params;
            if (!document_id) {
              throw new Error('document_id parameter is required for get_japan_dimensional_facts');
            }
    
            const results = await edinetApi.getDimensionalFacts(document_id, search_criteria || {});
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          // ============= KOREA DART METHODS =============
    
          case 'search_korea_companies': {
            const { query, limit } = params;
            if (!query) {
              throw new Error('query parameter is required for search_korea_companies');
            }
    
            const results = await dartApi.searchCompanies(query, { limit });
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_company_by_code': {
            const { corp_code } = params;
            if (!corp_code) {
              throw new Error('corp_code parameter is required for get_korea_company_by_code');
            }
    
            const result = await dartApi.getCompanyByCorpCode(corp_code);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(result, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_company_filings': {
            const { corp_code, start_date, end_date, report_type, limit } = params;
            if (!corp_code) {
              throw new Error('corp_code parameter is required for get_korea_company_filings');
            }
    
            const results = await dartApi.getCompanyFilings(corp_code, {
              startDate: start_date,
              endDate: end_date,
              reportType: report_type,
              limit
            });
    
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_financial_statements': {
            const { corp_code, business_year, report_code } = params;
            if (!corp_code || !business_year) {
              throw new Error('corp_code and business_year parameters are required for get_korea_financial_statements');
            }
    
            const results = await dartApi.getFinancialStatements(corp_code, business_year, report_code);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_major_shareholders': {
            const { corp_code } = params;
            if (!corp_code) {
              throw new Error('corp_code parameter is required for get_korea_major_shareholders');
            }
    
            const results = await dartApi.getMajorShareholders(corp_code);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_executive_info': {
            const { corp_code } = params;
            if (!corp_code) {
              throw new Error('corp_code parameter is required for get_korea_executive_info');
            }
    
            const results = await dartApi.getExecutiveInfo(corp_code);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_dividend_info': {
            const { corp_code, business_year } = params;
            if (!corp_code || !business_year) {
              throw new Error('corp_code and business_year parameters are required for get_korea_dividend_info');
            }
    
            const results = await dartApi.getDividendInfo(corp_code, business_year);
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'get_korea_dimensional_facts': {
            const { corp_code, business_year, report_code, search_criteria } = params;
            if (!corp_code || !business_year) {
              throw new Error('corp_code and business_year parameters are required for get_korea_dimensional_facts');
            }
    
            const results = await dartApi.getDimensionalFacts(
              corp_code,
              business_year,
              report_code || '11011',
              search_criteria || {}
            );
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          // ============= ADVANCED ANALYSIS METHODS (Phase 2) =============
    
          case 'build_fact_table':
          case 'search_facts_by_value': {
            const { country, company_id, target_value, tolerance, document_id, options } = params;
    
            if (!country || !company_id || target_value === undefined) {
              throw new Error('country, company_id, and target_value parameters are required for build_fact_table/search_facts_by_value');
            }
    
            const results = await factTableBuilder.buildFactTable({
              country,
              companyId: company_id,
              targetValue: target_value,
              tolerance: tolerance || 50000000,
              documentId: document_id,
              options: options || {}
            });
    
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          case 'time_series_analysis': {
            const { country, company_id, options } = params;
    
            if (!country || !company_id) {
              throw new Error('country and company_id parameters are required for time_series_analysis');
            }
    
            const results = await timeSeriesAnalyzer.timeSeriesAnalysis({
              country,
              companyId: company_id,
              options: options || {}
            });
    
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(results, null, 2)
                }
              ]
            };
          }
    
          // ============= UTILITY METHODS =============
    
          case 'filter_filings': {
            const { filings, filters } = params;
            if (!filings || !Array.isArray(filings)) {
              throw new Error('filings array parameter is required for filter_filings');
            }
    
            const results = dartApi.filterFilings(filings, filters || {});
            const response = {
              originalCount: filings.length,
              filteredCount: results.length,
              filters: filters || {},
              filings: results,
              source: 'Asia Filings Filter'
            };
    
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(response, null, 2)
                }
              ]
            };
          }
    
          default:
            throw new Error(`Unknown method: ${method}`);
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({ error: errorMessage }, null, 2)
            }
          ],
          isError: true
        };
      }
    });
  • Helper module implementing Japan EDINET API calls for company search, filings retrieval, document download, and XBRL fact extraction/parsing.
    import axios from 'axios';
    import * as xbrlParser from './xbrl-parser.js';
    
    const EDINET_API_BASE = 'https://disclosure.edinet-fsa.go.jp/api/v2';
    
    // API key should be set via environment variable or passed to functions
    const EDINET_API_KEY = process.env.EDINET_API_KEY || '';
    
    /**
     * Search for Japanese companies by name
     * @param {string} query - Company name to search (Japanese or English)
     * @param {Object} options - Search options
     * @returns {Promise<Object>} Search results
     */
    export async function searchCompanies(query, options = {}) {
      const { limit = 10, date } = options;
    
      try {
        // Get recent filings and search within them for company name
        const searchDate = date || new Date().toISOString().split('T')[0];
    
        const response = await axios.get(`${EDINET_API_BASE}/documents.json`, {
          params: {
            date: searchDate.replace(/-/g, ''),
            type: 2, // Type 2: Metadata only
          },
          headers: {
            'Subscription-Key': EDINET_API_KEY
          },
          timeout: 15000
        });
    
        if (!response.data || !response.data.results) {
          return {
            query,
            companies: [],
            total_found: 0,
            country: 'JP',
            source: 'EDINET API',
            note: 'No results found for the specified date'
          };
        }
    
        // Filter results by company name
        const queryLower = query.toLowerCase();
        const matchingCompanies = response.data.results
          .filter(doc => {
            const name = (doc.filerName || '').toLowerCase();
            return name.includes(queryLower);
          })
          .slice(0, limit)
          .map(doc => ({
            name: doc.filerName,
            edinet_code: doc.edinetCode,
            sec_code: doc.secCode || null,
            jcn: doc.JCN || null,
            recent_filing: {
              document_id: doc.docID,
              document_type: doc.docTypeCode,
              document_description: doc.docDescription,
              period_start: doc.periodStart,
              period_end: doc.periodEnd,
              submit_date: doc.submitDateTime
            }
          }));
    
        return {
          query,
          companies: matchingCompanies,
          total_found: matchingCompanies.length,
          country: 'JP',
          source: 'EDINET API',
          date_searched: searchDate
        };
    
      } catch (error) {
        if (error.response?.status === 401) {
          throw new Error('EDINET API key is required. Please set EDINET_API_KEY environment variable.');
        }
        throw new Error(`EDINET company search failed: ${error.message}`);
      }
    }
    
    /**
     * Get company information by EDINET code
     * @param {string} edinetCode - EDINET code (E-number)
     * @returns {Promise<Object>} Company information
     */
    export async function getCompanyByEdinetCode(edinetCode) {
      try {
        // Get recent filings for this company
        const today = new Date();
        const startDate = new Date(today.getFullYear() - 1, today.getMonth(), today.getDate());
    
        const filings = await getCompanyFilings(edinetCode, {
          startDate: startDate.toISOString().split('T')[0],
          endDate: today.toISOString().split('T')[0],
          limit: 1
        });
    
        if (!filings.filings || filings.filings.length === 0) {
          throw new Error(`No filings found for EDINET code: ${edinetCode}`);
        }
    
        const latestFiling = filings.filings[0];
    
        return {
          edinet_code: edinetCode,
          name: latestFiling.filer_name,
          sec_code: latestFiling.sec_code,
          jcn: latestFiling.jcn,
          latest_filing: {
            document_id: latestFiling.document_id,
            submit_date: latestFiling.submit_date,
            document_type: latestFiling.document_type
          },
          country: 'JP',
          source: 'EDINET API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get company by EDINET code: ${error.message}`);
      }
    }
    
    /**
     * Get company filings by EDINET code
     * @param {string} edinetCode - EDINET code
     * @param {Object} options - Options (startDate, endDate, limit)
     * @returns {Promise<Object>} Filings list
     */
    export async function getCompanyFilings(edinetCode, options = {}) {
      const { startDate, endDate, limit = 100 } = options;
    
      try {
        const start = startDate ? new Date(startDate) : new Date(Date.now() - 365 * 24 * 60 * 60 * 1000);
        const end = endDate ? new Date(endDate) : new Date();
    
        const allFilings = [];
    
        // Iterate through dates to find filings for this company
        const currentDate = new Date(start);
    
        while (currentDate <= end && allFilings.length < limit) {
          const dateStr = currentDate.toISOString().split('T')[0].replace(/-/g, '');
    
          try {
            const response = await axios.get(`${EDINET_API_BASE}/documents.json`, {
              params: {
                date: dateStr,
                type: 2
              },
              headers: {
                'Subscription-Key': EDINET_API_KEY
              },
              timeout: 15000
            });
    
            if (response.data?.results) {
              const companyFilings = response.data.results
                .filter(doc => doc.edinetCode === edinetCode)
                .map(doc => ({
                  document_id: doc.docID,
                  edinet_code: doc.edinetCode,
                  sec_code: doc.secCode,
                  jcn: doc.JCN,
                  filer_name: doc.filerName,
                  document_type: doc.docTypeCode,
                  document_description: doc.docDescription,
                  period_start: doc.periodStart,
                  period_end: doc.periodEnd,
                  submit_date: doc.submitDateTime,
                  xbrl_flag: doc.xbrlFlag === '1',
                  pdf_flag: doc.pdfFlag === '1',
                  urls: {
                    document: `${EDINET_API_BASE}/documents/${doc.docID}`,
                    viewer: `https://disclosure.edinet-fsa.go.jp/EKW0EZ0001.html?docID=${doc.docID}`
                  }
                }));
    
              allFilings.push(...companyFilings);
            }
          } catch (error) {
            // Skip dates with errors
          }
    
          // Move to next date
          currentDate.setDate(currentDate.getDate() + 1);
    
          // Rate limiting
          await new Promise(resolve => setTimeout(resolve, 200));
        }
    
        return {
          edinet_code: edinetCode,
          filings: allFilings.slice(0, limit),
          total_found: allFilings.length,
          date_range: {
            start: start.toISOString().split('T')[0],
            end: end.toISOString().split('T')[0]
          },
          source: 'EDINET API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get company filings: ${error.message}`);
      }
    }
    
    /**
     * Get filing document (download)
     * @param {string} docId - Document ID
     * @param {string} type - Document type (1: submission, 2: PDF, 3: attachments, 4: XBRL)
     * @returns {Promise<Object>} Document data
     */
    export async function getFilingDocument(docId, type = '1') {
      try {
        const response = await axios.get(`${EDINET_API_BASE}/documents/${docId}`, {
          params: { type },
          headers: {
            'Subscription-Key': EDINET_API_KEY
          },
          responseType: type === '4' ? 'arraybuffer' : 'stream',
          timeout: 30000
        });
    
        return {
          document_id: docId,
          type: type === '1' ? 'submission' : type === '2' ? 'pdf' : type === '3' ? 'attachments' : 'xbrl',
          data: response.data,
          content_type: response.headers['content-type']
        };
    
      } catch (error) {
        throw new Error(`Failed to download document: ${error.message}`);
      }
    }
    
    /**
     * Get documents list for a specific date
     * @param {string} date - Date in YYYY-MM-DD format
     * @returns {Promise<Object>} Documents list
     */
    export async function getDocumentsByDate(date) {
      try {
        const dateStr = date.replace(/-/g, '');
    
        const response = await axios.get(`${EDINET_API_BASE}/documents.json`, {
          params: {
            date: dateStr,
            type: 2
          },
          headers: {
            'Subscription-Key': EDINET_API_KEY
          },
          timeout: 15000
        });
    
        if (!response.data || !response.data.results) {
          return {
            date,
            documents: [],
            total_count: 0,
            source: 'EDINET API'
          };
        }
    
        return {
          date,
          documents: response.data.results.map(doc => ({
            document_id: doc.docID,
            edinet_code: doc.edinetCode,
            sec_code: doc.secCode,
            filer_name: doc.filerName,
            document_type: doc.docTypeCode,
            document_description: doc.docDescription,
            period_start: doc.periodStart,
            period_end: doc.periodEnd,
            submit_date: doc.submitDateTime,
            xbrl_flag: doc.xbrlFlag === '1'
          })),
          total_count: response.data.metadata?.resultset?.count || response.data.results.length,
          source: 'EDINET API'
        };
    
      } catch (error) {
        if (error.response?.status === 401) {
          throw new Error('EDINET API key is required. Please set EDINET_API_KEY environment variable.');
        }
        throw new Error(`Failed to get documents by date: ${error.message}`);
      }
    }
    
    /**
     * Get and parse XBRL facts from a filing
     * @param {string} docId - Document ID
     * @returns {Promise<Object>} Parsed XBRL facts
     */
    export async function getFilingFacts(docId) {
      try {
        // Download XBRL document (type 4)
        const response = await axios.get(`${EDINET_API_BASE}/documents/${docId}`, {
          params: { type: '4' },
          headers: {
            'Subscription-Key': EDINET_API_KEY
          },
          responseType: 'text',
          timeout: 30000
        });
    
        // Parse iXBRL HTML
        const parsed = xbrlParser.parseIXBRL(response.data);
    
        return {
          document_id: docId,
          ...parsed,
          summary: xbrlParser.buildSummary(parsed.facts)
        };
    
      } catch (error) {
        throw new Error(`Failed to get filing facts: ${error.message}`);
      }
    }
    
    /**
     * Get dimensional facts from a filing
     * @param {string} docId - Document ID
     * @param {Object} searchCriteria - Search criteria
     * @returns {Promise<Object>} Dimensional facts
     */
    export async function getDimensionalFacts(docId, searchCriteria = {}) {
      try {
        const { facts, ...metadata } = await getFilingFacts(docId);
    
        // Filter facts based on criteria
        let filteredFacts = facts;
        if (Object.keys(searchCriteria).length > 0) {
          filteredFacts = xbrlParser.filterFacts(facts, searchCriteria);
        }
    
        // Extract dimensional breakdowns
        const dimensions = xbrlParser.extractDimensions(filteredFacts);
    
        return {
          document_id: docId,
          search_criteria: searchCriteria,
          facts: filteredFacts,
          total_found: filteredFacts.length,
          dimensions,
          ...metadata
        };
    
      } catch (error) {
        throw new Error(`Failed to get dimensional facts: ${error.message}`);
      }
    }
    
    export default {
      searchCompanies,
      getCompanyByEdinetCode,
      getCompanyFilings,
      getFilingDocument,
      getDocumentsByDate,
      getFilingFacts,
      getDimensionalFacts
    };
  • Helper module implementing South Korea DART API calls for company search, filings, financial statements, shareholder/executive info, and XBRL facts.
    import axios from 'axios';
    import * as xbrlParser from './xbrl-parser.js';
    
    const DART_API_BASE = 'https://opendart.fss.or.kr/api';
    
    // API key should be set via environment variable
    const DART_API_KEY = process.env.DART_API_KEY || '';
    
    /**
     * Search Korean companies by name
     * @param {string} query - Company name to search
     * @param {Object} options - Search options
     * @returns {Promise<Object>} Search results
     */
    export async function searchCompanies(query, options = {}) {
      const { limit = 10 } = options;
    
      try {
        // Get company list (corp_code.xml contains all companies)
        // For now, we'll search through recent disclosures
        const response = await axios.get(`${DART_API_BASE}/list.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_name: query,
            bgn_de: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0].replace(/-/g, ''),
            end_de: new Date().toISOString().split('T')[0].replace(/-/g, ''),
            page_count: limit
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        const companies = [];
        const seenCodes = new Set();
    
        if (response.data.list) {
          for (const item of response.data.list) {
            if (!seenCodes.has(item.corp_code)) {
              seenCodes.add(item.corp_code);
              companies.push({
                name: item.corp_name,
                corp_code: item.corp_code,
                stock_code: item.stock_code || null,
                recent_filing: {
                  report_name: item.report_nm,
                  receipt_number: item.rcept_no,
                  report_date: item.rcept_dt,
                  remarks: item.rm
                }
              });
    
              if (companies.length >= limit) break;
            }
          }
        }
    
        return {
          query,
          companies,
          total_found: companies.length,
          country: 'KR',
          source: 'DART Open API'
        };
    
      } catch (error) {
        if (error.response?.data?.status === '020') {
          throw new Error('DART API key is required or invalid. Please set DART_API_KEY environment variable.');
        }
        throw new Error(`DART company search failed: ${error.message}`);
      }
    }
    
    /**
     * Get company information by corporate code
     * @param {string} corpCode - Corporate code
     * @returns {Promise<Object>} Company information
     */
    export async function getCompanyByCorpCode(corpCode) {
      try {
        const response = await axios.get(`${DART_API_BASE}/company.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_code: corpCode
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        return {
          corp_code: corpCode,
          name: response.data.corp_name,
          name_eng: response.data.corp_name_eng,
          stock_code: response.data.stock_code,
          ceo_name: response.data.ceo_nm,
          corporation_number: response.data.corp_cls,
          legal_form: response.data.corp_cls,
          business_registration_number: response.data.bizr_no,
          address: response.data.adres,
          homepage: response.data.hm_url,
          phone: response.data.phn_no,
          establishment_date: response.data.est_dt,
          accounting_month: response.data.acc_mt,
          country: 'KR',
          source: 'DART Open API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get company by corp code: ${error.message}`);
      }
    }
    
    /**
     * Get company filings/disclosures
     * @param {string} corpCode - Corporate code
     * @param {Object} options - Options (startDate, endDate, reportType, limit)
     * @returns {Promise<Object>} Filings list
     */
    export async function getCompanyFilings(corpCode, options = {}) {
      const {
        startDate,
        endDate,
        reportType = '', // A: Annual, Q: Quarterly, etc.
        limit = 100
      } = options;
    
      try {
        const start = startDate ? startDate.replace(/-/g, '') : new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0].replace(/-/g, '');
        const end = endDate ? endDate.replace(/-/g, '') : new Date().toISOString().split('T')[0].replace(/-/g, '');
    
        const response = await axios.get(`${DART_API_BASE}/list.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_code: corpCode,
            bgn_de: start,
            end_de: end,
            pblntf_ty: reportType,
            page_count: limit
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        const filings = (response.data.list || []).map(item => ({
          corp_code: item.corp_code,
          corp_name: item.corp_name,
          stock_code: item.stock_code,
          report_name: item.report_nm,
          receipt_number: item.rcept_no,
          filing_date: item.flr_nm,
          report_date: item.rcept_dt,
          remarks: item.rm,
          urls: {
            viewer: `https://dart.fss.or.kr/dsaf001/main.do?rcpNo=${item.rcept_no}`,
            document: `${DART_API_BASE}/document.xml?crtfc_key=${DART_API_KEY}&rcept_no=${item.rcept_no}`
          }
        }));
    
        return {
          corp_code: corpCode,
          filings,
          total_found: filings.length,
          date_range: {
            start: startDate || start,
            end: endDate || end
          },
          source: 'DART Open API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get company filings: ${error.message}`);
      }
    }
    
    /**
     * Get financial statements for a company
     * @param {string} corpCode - Corporate code
     * @param {string} businessYear - Business year (YYYY)
     * @param {string} reportCode - Report code (11013: Q1, 11012: Q2, 11014: Q3, 11011: Annual)
     * @returns {Promise<Object>} Financial statements
     */
    export async function getFinancialStatements(corpCode, businessYear, reportCode = '11011') {
      try {
        // Get consolidated financial statements
        const response = await axios.get(`${DART_API_BASE}/fnlttSinglAcntAll.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_code: corpCode,
            bsns_year: businessYear,
            reprt_code: reportCode
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        // Parse XBRL data
        const parsed = xbrlParser.parseXBRLJSON(response.data);
    
        return {
          corp_code: corpCode,
          business_year: businessYear,
          report_code: reportCode,
          report_type: reportCode === '11011' ? 'Annual' : reportCode === '11013' ? 'Q1' : reportCode === '11012' ? 'Q2' : 'Q3',
          statements: response.data.list || [],
          ...parsed,
          summary: xbrlParser.buildSummary(parsed.facts),
          source: 'DART Open API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get financial statements: ${error.message}`);
      }
    }
    
    /**
     * Get dimensional facts from financial statements
     * @param {string} corpCode - Corporate code
     * @param {string} businessYear - Business year (YYYY)
     * @param {string} reportCode - Report code
     * @param {Object} searchCriteria - Search criteria
     * @returns {Promise<Object>} Dimensional facts
     */
    export async function getDimensionalFacts(corpCode, businessYear, reportCode, searchCriteria = {}) {
      try {
        const { facts, ...metadata } = await getFinancialStatements(corpCode, businessYear, reportCode);
    
        // Filter facts based on criteria
        let filteredFacts = facts;
        if (Object.keys(searchCriteria).length > 0) {
          filteredFacts = xbrlParser.filterFacts(facts, searchCriteria);
        }
    
        // Extract dimensional breakdowns
        const dimensions = xbrlParser.extractDimensions(filteredFacts);
    
        return {
          corp_code: corpCode,
          business_year: businessYear,
          report_code: reportCode,
          search_criteria: searchCriteria,
          facts: filteredFacts,
          total_found: filteredFacts.length,
          dimensions,
          ...metadata
        };
    
      } catch (error) {
        throw new Error(`Failed to get dimensional facts: ${error.message}`);
      }
    }
    
    /**
     * Get major shareholder information
     * @param {string} corpCode - Corporate code
     * @returns {Promise<Object>} Major shareholder data
     */
    export async function getMajorShareholders(corpCode) {
      try {
        const response = await axios.get(`${DART_API_BASE}/majorstock.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_code: corpCode
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        return {
          corp_code: corpCode,
          shareholders: (response.data.list || []).map(item => ({
            report_date: item.rcept_dt,
            shareholder_name: item.nm,
            relation: item.relate,
            shares_owned: item.stock_knd,
            ownership_percent: item.hold_stock_ratio,
            change_reason: item.change_cause
          })),
          source: 'DART Open API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get major shareholders: ${error.message}`);
      }
    }
    
    /**
     * Get company executive information
     * @param {string} corpCode - Corporate code
     * @returns {Promise<Object>} Executive information
     */
    export async function getExecutiveInfo(corpCode) {
      try {
        const response = await axios.get(`${DART_API_BASE}/exctvSttus.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_code: corpCode
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        return {
          corp_code: corpCode,
          executives: (response.data.list || []).map(item => ({
            name: item.nm,
            position: item.sexdstn,
            registration_date: item.rcept_dt,
            birth_year: item.birth_ym,
            career: item.career
          })),
          source: 'DART Open API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get executive information: ${error.message}`);
      }
    }
    
    /**
     * Get dividend information
     * @param {string} corpCode - Corporate code
     * @param {string} businessYear - Business year (YYYY)
     * @returns {Promise<Object>} Dividend information
     */
    export async function getDividendInfo(corpCode, businessYear) {
      try {
        const response = await axios.get(`${DART_API_BASE}/alotMatter.json`, {
          params: {
            crtfc_key: DART_API_KEY,
            corp_code: corpCode,
            bsns_year: businessYear
          },
          timeout: 15000
        });
    
        if (response.data.status !== '000') {
          throw new Error(`DART API error: ${response.data.message}`);
        }
    
        return {
          corp_code: corpCode,
          business_year: businessYear,
          dividends: response.data.list || [],
          source: 'DART Open API'
        };
    
      } catch (error) {
        throw new Error(`Failed to get dividend information: ${error.message}`);
      }
    }
    
    /**
     * Filter filings by criteria
     * @param {Array} filings - Array of filings
     * @param {Object} filters - Filter criteria
     * @returns {Array} Filtered filings
     */
    export function filterFilings(filings, filters = {}) {
      const { startDate, endDate, reportType, hasXbrl } = filters;
    
      return filings.filter(filing => {
        if (startDate && filing.report_date < startDate.replace(/-/g, '')) return false;
        if (endDate && filing.report_date > endDate.replace(/-/g, '')) return false;
        if (reportType && !filing.report_name.includes(reportType)) return false;
        // Note: hasXbrl filter would require additional metadata
        return true;
      });
    }
    
    export default {
      searchCompanies,
      getCompanyByCorpCode,
      getCompanyFilings,
      getFinancialStatements,
      getMajorShareholders,
      getExecutiveInfo,
      getDividendInfo,
      filterFilings,
      getDimensionalFacts
    };
  • Advanced helper for building fact tables around target values with BI summaries, supporting both JP and KR filings with dimensional breakdowns.
    export async function buildFactTable(params) {
      const {
        country,
        companyId,
        targetValue,
        tolerance = 50000000,
        documentId = null,
        options = {}
      } = params;
    
      const defaultOptions = {
        maxRows: 25,
        showDimensions: true,
        sortBy: 'deviation', // 'deviation', 'value', 'concept'
        filters: {}
      };
    
      const tableOptions = { ...defaultOptions, ...options };
    
      try {
        let xbrlData;
        let filingInfo = {};
        let currencySymbol = country === 'JP' ? '¥' : '₩';
    
        // 1. Get XBRL data based on country
        if (country === 'JP') {
          // Japan - EDINET
          let targetDocId = documentId;
    
          if (!targetDocId) {
            // Get recent filing to find document ID
            const filings = await edinetApi.getCompanyFilings(companyId, { limit: 1 });
            if (!filings.filings || filings.filings.length === 0) {
              throw new Error('No filings found for company');
            }
            targetDocId = filings.filings[0].document_id;
            filingInfo = filings.filings[0];
          }
    
          xbrlData = await edinetApi.getFilingFacts(targetDocId);
          filingInfo.document_id = targetDocId;
    
        } else if (country === 'KR') {
          // Korea - DART
          if (!documentId) {
            throw new Error('business_year and report_code are required for Korean filings');
          }
    
          // documentId should be formatted as "businessYear:reportCode"
          const [businessYear, reportCode] = documentId.split(':');
          xbrlData = await dartApi.getFinancialStatements(companyId, businessYear, reportCode || '11011');
          filingInfo.business_year = businessYear;
          filingInfo.report_code = reportCode;
    
        } else {
          throw new Error('Unsupported country. Use JP for Japan or KR for Korea');
        }
    
        // 2. Find facts in value range
        const searchCriteria = {
          valueRange: {
            min: targetValue - tolerance,
            max: targetValue + tolerance
          },
          hasValue: true,
          ...tableOptions.filters
        };
    
        const matchingFacts = xbrlParser.filterFacts(xbrlData.facts, searchCriteria);
    
        if (matchingFacts.length === 0) {
          return {
            country,
            company: companyId,
            filing_info: filingInfo,
            targetValue,
            tolerance,
            searchRange: {
              min: targetValue - tolerance,
              max: targetValue + tolerance,
              minFormatted: formatCurrency(targetValue - tolerance, currencySymbol),
              maxFormatted: formatCurrency(targetValue + tolerance, currencySymbol)
            },
            table: [],
            summary: {
              totalFacts: 0,
              message: 'No facts found in the specified value range'
            }
          };
        }
    
        // 3. Enrich facts with business intelligence
        const enrichedFacts = matchingFacts.map((fact, index) => {
          const deviation = fact.value - targetValue;
          const exactMatch = Math.abs(deviation) < 1000;
    
          return {
            rowNumber: index + 1,
            concept: fact.concept,
            accountName: fact.accountName || null, // Korean-specific
            namespace: fact.namespace || 'unknown',
            value: fact.value,
            valueFormatted: formatCurrency(fact.value, currencySymbol),
            exactMatch,
            deviationFromTarget: deviation,
            deviationFormatted: `${deviation >= 0 ? '+' : ''}${formatCurrency(deviation, currencySymbol)}`,
            deviationPercent: targetValue !== 0 ? ((deviation / targetValue) * 100).toFixed(2) + '%' : 'N/A',
    
            periodType: fact.period?.instant ? 'instant' : 'duration',
            periodStart: fact.period?.startDate,
            periodEnd: fact.period?.endDate || fact.period?.instant,
    
            dimensions: fact.dimensions || {},
            dimensionCount: Object.keys(fact.dimensions || {}).length,
    
            geography: extractGeographyFromDimensions(fact.dimensions),
            segment: extractSegmentFromDimensions(fact.dimensions),
            product: extractProductFromDimensions(fact.dimensions),
    
            hasGeographicDimension: hasGeographyDimension(fact.dimensions),
            hasSegmentDimension: hasSegmentDimension(fact.dimensions),
            hasProductDimension: hasProductDimension(fact.dimensions),
    
            businessClassification: xbrlParser.classifyFact(fact.concept, country === 'JP' ? 'J-GAAP' : 'K-GAAP'),
    
            contextRef: fact.contextRef,
            unitRef: fact.unitRef || fact.unit,
            decimals: fact.decimals,
            scale: fact.scale
          };
        });
    
        // 4. Sort based on options
        sortFacts(enrichedFacts, tableOptions.sortBy);
    
        // 5. Limit results
        const limitedFacts = enrichedFacts.slice(0, tableOptions.maxRows);
    
        // 6. Generate business intelligence summary
        const summary = generateFactTableSummary(enrichedFacts, targetValue, tolerance, currencySymbol);
    
        return {
          country,
          company: companyId,
          filing_info: filingInfo,
          targetValue,
          tolerance,
          searchRange: {
            min: targetValue - tolerance,
            max: targetValue + tolerance,
            minFormatted: formatCurrency(targetValue - tolerance, currencySymbol),
            maxFormatted: formatCurrency(targetValue + tolerance, currencySymbol)
          },
          table: limitedFacts,
          summary,
          totalFactsFound: enrichedFacts.length,
          totalFactsReturned: limitedFacts.length,
          source: country === 'JP' ? 'EDINET J-GAAP Analysis' : 'DART K-GAAP Analysis',
          taxonomy: country === 'JP' ? 'J-GAAP' : 'K-GAAP/IFRS'
        };
    
      } catch (error) {
        throw new Error(`Failed to build fact table: ${error.message}`);
      }
    }

Tool Definition Quality

Score is being calculated. Check back soon.

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/openpharma-org/asia-filings-mcp-server'

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