openfigi-mcp 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,21 @@
1
+ #!/usr/bin/env node
1
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
4
  import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
4
5
  import { createClient, isValidBloombergId, isValidCUSIP, isValidISIN, isValidSEDOL } from "openfigi-sdk";
5
6
 
7
+ //#region src/polyfill.ts
8
+ if (typeof globalThis.fetch === "undefined") {
9
+ const { fetch, Headers, Request, Response } = await import("undici");
10
+ Object.assign(globalThis, {
11
+ fetch,
12
+ Headers,
13
+ Request,
14
+ Response
15
+ });
16
+ }
17
+
18
+ //#endregion
6
19
  //#region src/tools/index.ts
7
20
  const filterProperties = {
8
21
  exchCode: {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["array: T[]","size: number","chunks: T[][]","args: Record<string, unknown>","identifier: string","text: string","identifiers: DetectedIdentifier[]","typeCounts: Record<IdentifierType, number>","response: MappingResponse","result: FigiResult","index: number","name: string","requests: MappingRequest[]","allResponses: MappingResponse[]","idTypeMap: Record<IdentifierType, MappingRequest['idType']>","found: string[]","notFound: string[]","uri: string"],"sources":["../src/tools/index.ts","../src/resources/index.ts","../src/index.ts"],"sourcesContent":["import {\n createClient,\n isValidISIN,\n isValidCUSIP,\n isValidSEDOL,\n isValidBloombergId,\n type MappingRequest,\n type MappingResponse,\n type FigiResult,\n} from 'openfigi-sdk'\n\ninterface SearchFilters {\n exchCode?: string\n micCode?: string\n currency?: string\n marketSecDes?: string\n securityType?: string\n includeUnlistedEquities?: boolean\n}\n\n// Common filter properties for JSON schema\nconst filterProperties = {\n exchCode: {\n type: 'string',\n description: 'Exchange code filter (e.g., \"US\", \"NASDAQ\")',\n },\n micCode: {\n type: 'string',\n description: 'MIC code filter (e.g., \"XNAS\", \"XNYS\")',\n },\n currency: {\n type: 'string',\n description: 'Currency filter (e.g., \"USD\", \"EUR\")',\n },\n marketSecDes: {\n type: 'string',\n description: 'Market sector filter (e.g., \"Equity\", \"Corp\")',\n },\n securityType: {\n type: 'string',\n description: 'Security type filter (e.g., \"Common Stock\")',\n },\n includeUnlistedEquities: {\n type: 'boolean',\n description: 'Include unlisted equities',\n },\n} as const\n\n// Create client with API key from environment\nconst getClient = () => {\n const apiKey = process.env.OPENFIGI_API_KEY\n return createClient({ apiKey })\n}\n\n// Check if API key is configured\nconst hasApiKey = () => Boolean(process.env.OPENFIGI_API_KEY)\n\n// Batch size limits based on API key presence\nconst getBatchSize = () => (hasApiKey() ? 100 : 10)\n\n// Helper to chunk array into smaller batches\nconst chunkArray = <T>(array: T[], size: number): T[][] => {\n const chunks: T[][] = []\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size))\n }\n return chunks\n}\n\n// Extract filter properties from args\nconst extractFilters = (args: Record<string, unknown>): SearchFilters => ({\n exchCode: args.exchCode as string | undefined,\n micCode: args.micCode as string | undefined,\n currency: args.currency as string | undefined,\n marketSecDes: args.marketSecDes as string | undefined,\n securityType: args.securityType as string | undefined,\n includeUnlistedEquities: args.includeUnlistedEquities as boolean | undefined,\n})\n\n// Detect identifier type from a string\ntype IdentifierType = 'ISIN' | 'CUSIP' | 'SEDOL' | 'BLOOMBERG_ID' | 'TICKER' | 'UNKNOWN'\n\ninterface DetectedIdentifier {\n value: string\n type: IdentifierType\n exchCode?: string\n confidence: 'high' | 'medium' | 'low'\n}\n\nconst detectIdentifierType = (identifier: string): DetectedIdentifier => {\n const trimmed = identifier.trim()\n\n // Check for ISIN (12 chars, 2 letter country code + 9 alphanumeric + 1 check digit)\n if (isValidISIN(trimmed)) {\n return { value: trimmed, type: 'ISIN', confidence: 'high' }\n }\n\n // Check for Bloomberg ID (starts with BBG)\n if (isValidBloombergId(trimmed)) {\n return { value: trimmed, type: 'BLOOMBERG_ID', confidence: 'high' }\n }\n\n // Check for CUSIP (9 alphanumeric)\n if (isValidCUSIP(trimmed)) {\n return { value: trimmed, type: 'CUSIP', confidence: 'medium' }\n }\n\n // Check for SEDOL (7 alphanumeric)\n if (isValidSEDOL(trimmed)) {\n return { value: trimmed, type: 'SEDOL', confidence: 'medium' }\n }\n\n // Check for ticker with exchange suffix (e.g., \"AAPL US\", \"ABLI SS\")\n const tickerWithExchange = trimmed.match(/^([A-Z0-9]+)\\s+([A-Z]{2})$/i)\n if (tickerWithExchange) {\n return {\n value: tickerWithExchange[1].toUpperCase(),\n type: 'TICKER',\n exchCode: tickerWithExchange[2].toUpperCase(),\n confidence: 'high',\n }\n }\n\n // Check for simple ticker (all caps, 1-5 chars)\n if (/^[A-Z]{1,5}$/.test(trimmed)) {\n return { value: trimmed, type: 'TICKER', confidence: 'low' }\n }\n\n // Check for ticker with numbers (e.g., \"BRK.A\", \"TSLA3\")\n if (/^[A-Z0-9.]{1,10}$/i.test(trimmed)) {\n return { value: trimmed.toUpperCase(), type: 'TICKER', confidence: 'low' }\n }\n\n return { value: trimmed, type: 'UNKNOWN', confidence: 'low' }\n}\n\n// Parse CSV/text data and detect identifiers\nconst parseAndDetectIdentifiers = (\n text: string\n): { identifiers: DetectedIdentifier[]; summary: string } => {\n const lines = text.split(/\\r?\\n/).filter((line) => line.trim())\n const identifiers: DetectedIdentifier[] = []\n const typeCounts: Record<IdentifierType, number> = {\n ISIN: 0,\n CUSIP: 0,\n SEDOL: 0,\n BLOOMBERG_ID: 0,\n TICKER: 0,\n UNKNOWN: 0,\n }\n\n // Check if first line looks like a header\n const firstLine = lines[0]?.trim().toLowerCase()\n const hasHeader =\n firstLine?.includes('ticker') ||\n firstLine?.includes('isin') ||\n firstLine?.includes('cusip') ||\n firstLine?.includes('sedol') ||\n firstLine?.includes('symbol') ||\n firstLine?.includes('identifier')\n\n const dataLines = hasHeader ? lines.slice(1) : lines\n\n for (const line of dataLines) {\n // Handle CSV/tab-separated: take first column\n const columns = line.split(/[,\\t]/)\n const value = columns[0]?.trim()\n\n if (value && value.length > 0) {\n const detected = detectIdentifierType(value)\n identifiers.push(detected)\n typeCounts[detected.type]++\n }\n }\n\n const summary = [\n `Detected ${identifiers.length} identifiers:`,\n typeCounts.ISIN > 0 ? ` - ISIN: ${typeCounts.ISIN}` : null,\n typeCounts.CUSIP > 0 ? ` - CUSIP: ${typeCounts.CUSIP}` : null,\n typeCounts.SEDOL > 0 ? ` - SEDOL: ${typeCounts.SEDOL}` : null,\n typeCounts.BLOOMBERG_ID > 0\n ? ` - Bloomberg ID: ${typeCounts.BLOOMBERG_ID}`\n : null,\n typeCounts.TICKER > 0 ? ` - Ticker: ${typeCounts.TICKER}` : null,\n typeCounts.UNKNOWN > 0 ? ` - Unknown: ${typeCounts.UNKNOWN}` : null,\n ]\n .filter(Boolean)\n .join('\\n')\n\n return { identifiers, summary }\n}\n\n// Format a mapping response for display\nconst formatResponse = (response: MappingResponse): string => {\n if (response.error) {\n return `Error: ${response.error}`\n }\n if (response.warning) {\n return `Warning: ${response.warning}`\n }\n if (!response.data || response.data.length === 0) {\n return 'No results found'\n }\n\n return response.data\n .map((result: FigiResult, index: number) => {\n const lines = [`Result ${index + 1}:`]\n lines.push(` FIGI: ${result.figi}`)\n if (result.name) lines.push(` Name: ${result.name}`)\n if (result.ticker) lines.push(` Ticker: ${result.ticker}`)\n if (result.exchCode) lines.push(` Exchange: ${result.exchCode}`)\n if (result.marketSector) lines.push(` Market Sector: ${result.marketSector}`)\n if (result.securityType) lines.push(` Security Type: ${result.securityType}`)\n if (result.compositeFIGI) lines.push(` Composite FIGI: ${result.compositeFIGI}`)\n if (result.shareClassFIGI) lines.push(` Share Class FIGI: ${result.shareClassFIGI}`)\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\n// Tool definitions\nexport const toolDefinitions = [\n {\n name: 'search_by_isin',\n description:\n 'Search for financial instruments by ISIN (International Securities Identification Number). Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n isin: {\n type: 'string',\n description: 'ISIN to search for (e.g., \"US0378331005\" for Apple)',\n },\n ...filterProperties,\n },\n required: ['isin'],\n },\n },\n {\n name: 'search_by_cusip',\n description:\n 'Search for financial instruments by CUSIP (Committee on Uniform Securities Identification Procedures). Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n cusip: {\n type: 'string',\n description: 'CUSIP to search for (e.g., \"037833100\" for Apple)',\n },\n ...filterProperties,\n },\n required: ['cusip'],\n },\n },\n {\n name: 'search_by_sedol',\n description:\n 'Search for financial instruments by SEDOL (Stock Exchange Daily Official List). Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n sedol: {\n type: 'string',\n description: 'SEDOL to search for (e.g., \"2046251\" for Apple)',\n },\n ...filterProperties,\n },\n required: ['sedol'],\n },\n },\n {\n name: 'search_by_ticker',\n description:\n 'Search for financial instruments by ticker symbol. Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n ticker: {\n type: 'string',\n description: 'Ticker symbol to search for (e.g., \"AAPL\")',\n },\n exchCode: {\n type: 'string',\n description: 'Exchange code to narrow search (e.g., \"US\", \"NASDAQ\")',\n },\n micCode: filterProperties.micCode,\n currency: filterProperties.currency,\n marketSecDes: filterProperties.marketSecDes,\n securityType: filterProperties.securityType,\n includeUnlistedEquities: filterProperties.includeUnlistedEquities,\n },\n required: ['ticker'],\n },\n },\n {\n name: 'search_by_bloomberg_id',\n description:\n 'Search for financial instruments by Bloomberg Global ID. Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n bloombergId: {\n type: 'string',\n description: 'Bloomberg Global ID to search for (e.g., \"BBG000B9XRY4\")',\n },\n ...filterProperties,\n },\n required: ['bloombergId'],\n },\n },\n {\n name: 'batch_mapping',\n description:\n 'Map multiple financial identifiers to FIGIs in a single request. Supports up to 100 identifiers per request.',\n inputSchema: {\n type: 'object',\n properties: {\n identifiers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n idType: {\n type: 'string',\n description:\n 'Type of identifier (e.g., \"ID_ISIN\", \"ID_CUSIP\", \"ID_SEDOL\", \"ID_EXCH_SYMBOL\", \"ID_BB_GLOBAL\")',\n },\n idValue: {\n type: 'string',\n description: 'The identifier value',\n },\n exchCode: {\n type: 'string',\n description: 'Optional exchange code filter',\n },\n },\n required: ['idType', 'idValue'],\n },\n description: 'Array of identifiers to map (max 100)',\n },\n },\n required: ['identifiers'],\n },\n },\n {\n name: 'validate_identifier',\n description:\n 'Validate the format of a financial identifier (ISIN, CUSIP, SEDOL, or Bloomberg ID).',\n inputSchema: {\n type: 'object',\n properties: {\n identifier: {\n type: 'string',\n description: 'The identifier to validate',\n },\n type: {\n type: 'string',\n enum: ['ISIN', 'CUSIP', 'SEDOL', 'BLOOMBERG_ID'],\n description: 'Type of identifier to validate',\n },\n },\n required: ['identifier', 'type'],\n },\n },\n {\n name: 'get_rate_limit_status',\n description: 'Get the current OpenFIGI API rate limit status.',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'parse_identifiers',\n description:\n 'Parse and auto-detect financial identifiers from CSV/text data. Supports tickers with exchange codes (e.g., \"AAPL US\", \"ABLI SS\"), ISINs, CUSIPs, SEDOLs, and Bloomberg IDs. Automatically detects the identifier type and extracts exchange codes when present.',\n inputSchema: {\n type: 'object',\n properties: {\n text: {\n type: 'string',\n description:\n 'CSV or newline-separated text containing identifiers. Can include headers. Example: \"Ticker\\\\nABLI SS\\\\nACE SS\"',\n },\n },\n required: ['text'],\n },\n },\n {\n name: 'search_auto_detect',\n description:\n 'Automatically detect the identifier type and search for a single financial instrument. Supports ISINs, CUSIPs, SEDOLs, Bloomberg IDs, and tickers with optional exchange codes (e.g., \"AAPL US\").',\n inputSchema: {\n type: 'object',\n properties: {\n identifier: {\n type: 'string',\n description:\n 'The identifier to search for. Type will be auto-detected. Examples: \"US0378331005\" (ISIN), \"037833100\" (CUSIP), \"AAPL US\" (ticker with exchange)',\n },\n },\n required: ['identifier'],\n },\n },\n {\n name: 'batch_search_auto_detect',\n description:\n 'Parse identifiers from text/CSV and search for all of them in a single batch operation. Automatically detects identifier types. Great for processing lists of tickers or identifiers from spreadsheets.',\n inputSchema: {\n type: 'object',\n properties: {\n text: {\n type: 'string',\n description:\n 'CSV or newline-separated text containing identifiers. Example: \"Ticker\\\\nABLI SS\\\\nACE SS\\\\nACTI SS\"',\n },\n },\n required: ['text'],\n },\n },\n] as const\n\n// Tool handlers\nexport async function handleTool(\n name: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: 'text'; text: string }> }> {\n const client = getClient()\n\n try {\n switch (name) {\n case 'search_by_isin': {\n const isin = args.isin as string\n const filters = extractFilters(args)\n const response = await client.searchByISIN(isin, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_cusip': {\n const cusip = args.cusip as string\n const filters = extractFilters(args)\n const response = await client.searchByCUSIP(cusip, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_sedol': {\n const sedol = args.sedol as string\n const filters = extractFilters(args)\n const response = await client.searchBySEDOL(sedol, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_ticker': {\n const ticker = args.ticker as string\n const exchCode = args.exchCode as string | undefined\n const filters = extractFilters(args)\n const response = await client.searchByTicker(ticker, exchCode, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_bloomberg_id': {\n const bloombergId = args.bloombergId as string\n const filters = extractFilters(args)\n const response = await client.searchByBloombergId(bloombergId, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'batch_mapping': {\n const { identifiers } = args as {\n identifiers: Array<{\n idType: string\n idValue: string\n exchCode?: string\n }>\n }\n\n const requests: MappingRequest[] = identifiers.map((id) => ({\n idType: id.idType as MappingRequest['idType'],\n idValue: id.idValue,\n exchCode: id.exchCode as MappingRequest['exchCode'],\n }))\n\n // Split into batches based on API key presence\n const batchSize = getBatchSize()\n const batches = chunkArray(requests, batchSize)\n\n // Process all batches and combine results\n const allResponses: MappingResponse[] = []\n for (const batch of batches) {\n const batchResponses = await client.mapping(batch)\n allResponses.push(...batchResponses)\n }\n const responses = allResponses\n const formatted = responses\n .map((response: MappingResponse, index: number) => {\n const id = identifiers[index]\n return `[${index + 1}] ${id.idType}: ${id.idValue}\\n${formatResponse(response)}`\n })\n .join('\\n\\n---\\n\\n')\n\n return { content: [{ type: 'text', text: formatted }] }\n }\n\n case 'validate_identifier': {\n const { identifier, type } = args as {\n identifier: string\n type: 'ISIN' | 'CUSIP' | 'SEDOL' | 'BLOOMBERG_ID'\n }\n\n let isValid = false\n let format = ''\n\n switch (type) {\n case 'ISIN':\n isValid = isValidISIN(identifier)\n format = '2 letter country code + 9 alphanumeric characters + 1 check digit'\n break\n case 'CUSIP':\n isValid = isValidCUSIP(identifier)\n format = '9 alphanumeric characters'\n break\n case 'SEDOL':\n isValid = isValidSEDOL(identifier)\n format = '7 alphanumeric characters'\n break\n case 'BLOOMBERG_ID':\n isValid = isValidBloombergId(identifier)\n format = 'BBG + 9 alphanumeric characters'\n break\n }\n\n const result = isValid\n ? `Valid ${type}: \"${identifier}\"`\n : `Invalid ${type}: \"${identifier}\"\\nExpected format: ${format}`\n\n return { content: [{ type: 'text', text: result }] }\n }\n\n case 'get_rate_limit_status': {\n const rateLimit = client.getRateLimitInfo()\n\n if (!rateLimit) {\n return {\n content: [\n {\n type: 'text',\n text: 'No rate limit information available. Make a request first to get rate limit data.',\n },\n ],\n }\n }\n\n const text = [\n 'OpenFIGI API Rate Limit Status:',\n ` Limit: ${rateLimit.limit} requests`,\n ` Remaining: ${rateLimit.remaining} requests`,\n ` Resets: ${rateLimit.reset.toISOString()}`,\n ].join('\\n')\n\n return { content: [{ type: 'text', text }] }\n }\n\n case 'parse_identifiers': {\n const text = args.text as string\n const { identifiers, summary } = parseAndDetectIdentifiers(text)\n\n const details = identifiers\n .map((id, index) => {\n const exchPart = id.exchCode ? ` (Exchange: ${id.exchCode})` : ''\n return `${index + 1}. \"${id.value}\" → ${id.type}${exchPart} [${id.confidence} confidence]`\n })\n .join('\\n')\n\n return {\n content: [\n {\n type: 'text',\n text: `${summary}\\n\\nDetails:\\n${details}`,\n },\n ],\n }\n }\n\n case 'search_auto_detect': {\n const identifier = args.identifier as string\n const detected = detectIdentifierType(identifier)\n\n if (detected.type === 'UNKNOWN') {\n return {\n content: [\n {\n type: 'text',\n text: `Could not determine identifier type for \"${identifier}\". Please use a specific search tool or provide more context.`,\n },\n ],\n }\n }\n\n let response: MappingResponse\n\n switch (detected.type) {\n case 'ISIN':\n response = await client.searchByISIN(detected.value)\n break\n case 'CUSIP':\n response = await client.searchByCUSIP(detected.value)\n break\n case 'SEDOL':\n response = await client.searchBySEDOL(detected.value)\n break\n case 'BLOOMBERG_ID':\n response = await client.searchByBloombergId(detected.value)\n break\n case 'TICKER':\n response = await client.searchByTicker(detected.value, detected.exchCode)\n break\n }\n\n const header = `Detected type: ${detected.type}${detected.exchCode ? ` (Exchange: ${detected.exchCode})` : ''} [${detected.confidence} confidence]\\n\\n`\n const hasResults = response.data && response.data.length > 0\n const notFoundWarning = hasResults ? '' : `⚠️ NOT FOUND: \"${detected.value}\"${detected.exchCode ? ` on exchange ${detected.exchCode}` : ''} returned no results.\\n\\n`\n return { content: [{ type: 'text', text: header + notFoundWarning + formatResponse(response) }] }\n }\n\n case 'batch_search_auto_detect': {\n const text = args.text as string\n const { identifiers, summary } = parseAndDetectIdentifiers(text)\n\n // Filter out unknown identifiers\n const validIdentifiers = identifiers.filter((id) => id.type !== 'UNKNOWN')\n\n if (validIdentifiers.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: `${summary}\\n\\nNo valid identifiers found to search.`,\n },\n ],\n }\n }\n\n // Convert to mapping requests\n const idTypeMap: Record<IdentifierType, MappingRequest['idType']> = {\n ISIN: 'ID_ISIN',\n CUSIP: 'ID_CUSIP',\n SEDOL: 'ID_SEDOL',\n BLOOMBERG_ID: 'ID_BB_GLOBAL',\n TICKER: 'ID_EXCH_SYMBOL',\n UNKNOWN: 'ID_EXCH_SYMBOL', // Won't be used\n }\n\n const requests: MappingRequest[] = validIdentifiers.map((id) => ({\n idType: idTypeMap[id.type],\n idValue: id.value,\n exchCode: id.exchCode as MappingRequest['exchCode'],\n // securityType2 is required for ID_EXCH_SYMBOL (ticker) searches\n ...(id.type === 'TICKER' && { securityType2: 'Common Stock' as const }),\n }))\n\n // Split into batches based on API key presence\n const batchSize = getBatchSize()\n const batches = chunkArray(requests, batchSize)\n\n // Process all batches and combine results\n const allResponses: MappingResponse[] = []\n for (const batch of batches) {\n const batchResponses = await client.mapping(batch)\n allResponses.push(...batchResponses)\n }\n const responses = allResponses\n // Track found and not found\n const found: string[] = []\n const notFound: string[] = []\n\n const formatted = responses\n .map((response: MappingResponse, index: number) => {\n const id = validIdentifiers[index]\n const exchPart = id.exchCode ? ` [${id.exchCode}]` : ''\n const idLabel = `${id.value}${exchPart}`\n\n // Check if no results\n const hasResults = response.data && response.data.length > 0\n if (hasResults) {\n found.push(idLabel)\n } else {\n notFound.push(idLabel)\n }\n\n const status = hasResults ? '' : ' ⚠️ NOT FOUND'\n return `[${index + 1}] ${id.type}: ${idLabel}${status}\\n${formatResponse(response)}`\n })\n .join('\\n\\n---\\n\\n')\n\n // Add summary of found/not found\n const resultSummary = [\n `\\nResults: ${found.length} found, ${notFound.length} not found`,\n notFound.length > 0 ? `\\n⚠️ Not found:\\n${notFound.map((id) => ` - ${id}`).join('\\n')}` : '',\n ].join('')\n\n return { content: [{ type: 'text', text: `${summary}\\n\\n${formatted}\\n\\n---${resultSummary}` }] }\n }\n\n default:\n return {\n content: [{ type: 'text', text: `Unknown tool: ${name}` }],\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return { content: [{ type: 'text', text: `Error: ${message}` }] }\n }\n}\n","// Resource definitions for OpenFIGI MCP server\n// These provide reference data for identifier types, exchange codes, security types, etc.\n\nexport const resourceDefinitions = [\n {\n uri: 'openfigi://search-guide',\n name: 'Search Guide',\n description: 'IMPORTANT: Read this first! Guide on how to effectively search for securities using OpenFIGI',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://identifier-types',\n name: 'Identifier Types',\n description: 'List of supported financial identifier types for OpenFIGI API',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://exchange-codes',\n name: 'Exchange Codes',\n description: 'Common exchange codes used in OpenFIGI API',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://security-types',\n name: 'Security Types',\n description: 'Common security types used in OpenFIGI API',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://market-sectors',\n name: 'Market Sectors',\n description: 'Market sector values used in OpenFIGI API',\n mimeType: 'text/plain',\n },\n] as const\n\n// Search guide content - helps AI understand how to search effectively\nconst searchGuideContent = `OpenFIGI Search Guide\n=====================\n\n## Best Practices for Searching Securities\n\n### 1. PREFER ISIN OVER TICKER\nISINs are globally unique and always return accurate results:\n- ISIN format: 2-letter country code + 9 alphanumeric + 1 check digit\n- Example: US0378331005 (Apple), SE0000108656 (Ericsson)\n- Use search_by_isin for the most reliable results\n\n### 2. TICKER SEARCH REQUIREMENTS\nWhen searching by ticker (search_by_ticker or search_auto_detect):\n- MUST include exchange code for accurate results\n- Uses securityType2=\"Common Stock\" by default\n- Swedish tickers need share class: \"ERIC B\" not \"ERIC\"\n- US tickers: \"AAPL\" with exchCode \"US\"\n\n### 3. EXCHANGE CODE MAPPING\nCommon Bloomberg-style suffixes and their OpenFIGI exchCode:\n- \"SS\" → exchCode: \"SS\" (Stockholm/Nasdaq Nordic)\n- \"US\" → exchCode: \"US\" (United States)\n- \"LN\" → exchCode: \"LONDON\" or \"LSE\"\n- \"GY\" or \"GR\" → exchCode: \"XETRA\" or \"FRANKFURT\"\n- \"FP\" → exchCode: \"EURONEXT-PARIS\"\n- \"NA\" → exchCode: \"EURONEXT-AMSTER\"\n- \"FH\" → exchCode: \"FH\" (Helsinki)\n- \"DC\" → exchCode: \"NOMX COPENHAGEN\"\n- \"NO\" → exchCode: \"OSLO\"\n- \"JP\" → exchCode: \"TOKYO\"\n- \"HK\" → exchCode: \"HONG KONG\"\n\n### 4. NORDIC STOCK TICKER CONVENTIONS\nNordic stocks often have share class suffixes:\n- A shares: \"VOLV A SS\" (Volvo A shares)\n- B shares: \"ERIC B SS\" (Ericsson B shares)\n- Common pattern: TICKER + space + CLASS + space + EXCHANGE\n- If search fails, try adding \"A\" or \"B\" suffix\n\n### 5. HANDLING \"NOT FOUND\" RESULTS\nIf a ticker search returns no results:\n1. Check if share class is needed (add A/B suffix)\n2. Try without exchange code for broader search\n3. Search by ISIN if available (most reliable)\n4. Check if company uses different ticker in OpenFIGI\n\n### 6. BATCH SEARCH TIPS\nFor batch_search_auto_detect:\n- Supports ISINs, tickers with exchange codes, CUSIPs, SEDOLs\n- Format: \"TICKER EXCHANGE\" on each line (e.g., \"AAPL US\")\n- Automatically splits into smaller batches\n- Mix of identifier types is supported\n\n### 7. DATA SOURCE FORMATS\nDifferent data sources format tickers differently:\n\nBloomberg: \"AAPL US Equity\" → use \"AAPL\" with exchCode \"US\"\nFactSet: \"AAPL-US\" → use \"AAPL\" with exchCode \"US\"\nReuters: \"AAPL.O\" → use \"AAPL\" with exchCode \"NASDAQ\"\n\n### 8. WHEN TO USE WHICH TOOL\n- search_by_isin: Best for accuracy, use when ISIN is available\n- search_by_ticker: When you have ticker + exchange\n- search_auto_detect: Single identifier, type unknown\n- batch_search_auto_detect: Multiple identifiers from spreadsheet/CSV\n- search_by_cusip: US securities with CUSIP\n- search_by_sedol: UK/Irish securities with SEDOL\n\n### 9. COMMON PITFALLS\n- Ticker without exchange: May return too many or zero results\n- Wrong exchange code: \"NASDAQ\" vs \"US\" can give different results\n- Missing share class: Nordic stocks often need A/B suffix\n- Case sensitivity: Tickers are converted to uppercase automatically\n`\n\n// Identifier types content\nconst identifierTypesContent = `OpenFIGI Identifier Types\n========================\n\nThe OpenFIGI API supports the following identifier types (idType):\n\nPrimary Identifiers:\n- ID_ISIN: International Securities Identification Number (12 characters, e.g., US0378331005)\n- ID_CUSIP: Committee on Uniform Securities Identification Procedures (9 characters, e.g., 037833100)\n- ID_SEDOL: Stock Exchange Daily Official List (7 characters, e.g., 2046251)\n- ID_EXCH_SYMBOL: Exchange ticker symbol (e.g., AAPL)\n\nBloomberg Identifiers:\n- ID_BB_GLOBAL: Bloomberg Global Identifier (e.g., BBG000B9XRY4)\n- ID_BB: Bloomberg ID\n- ID_BB_UNIQUE: Bloomberg Unique ID\n- ID_BB_SEC_NUM: Bloomberg Security Number\n- ID_BB_SEC_NUM_DES: Bloomberg Security Number Description\n- ID_BB_GLOBAL_SHARE_CLASS_LEVEL: Bloomberg Share Class Level FIGI\n- COMPOSITE_ID_BB_GLOBAL: Bloomberg Composite Global ID\n\nRegional Identifiers:\n- ID_CINS: CUSIP International Numbering System\n- ID_COMMON: Common Code (used in Euroclear/Clearstream)\n- ID_WERTPAPIER: German securities identifier (WKN)\n- ID_BELGIUM: Belgian securities identifier\n- ID_DENMARK: Danish securities identifier (Fondskode)\n- ID_FRANCE: French securities identifier (SICOVAM)\n- ID_ITALY: Italian securities identifier (Codice ABI)\n- ID_JAPAN: Japanese securities identifier\n- ID_LUXEMBOURG: Luxembourg securities identifier\n- ID_NETHERLANDS: Dutch securities identifier\n- ID_POLAND: Polish securities identifier\n- ID_PORTUGAL: Portuguese securities identifier\n- ID_SWEDEN: Swedish securities identifier\n\nOther:\n- ID_FULL_EXCHANGE_SYMBOL: Full exchange symbol including exchange identifier\n- ID_SHORT_CODE: Short code identifier\n\nUsage Example:\n{\n \"idType\": \"ID_ISIN\",\n \"idValue\": \"US0378331005\"\n}\n`\n\n// Exchange codes content (subset of most common)\nconst exchangeCodesContent = `OpenFIGI Exchange Codes\n======================\n\nCommon Exchange Codes (exchCode):\n\nUnited States:\n- US: United States\n- NASDAQ: NASDAQ Stock Exchange\n- NYSE: New York Stock Exchange\n- NYSE AMERICAN: NYSE American (formerly AMEX)\n- NYSE ARCA: NYSE Arca\n- CBOE: Chicago Board Options Exchange\n- CME: Chicago Mercantile Exchange\n\nEurope:\n- LONDON: London Stock Exchange\n- LSE: London Stock Exchange\n- EURONEXT-PARIS: Euronext Paris\n- EURONEXT-AMSTER: Euronext Amsterdam\n- XETRA: Deutsche Börse XETRA\n- FRANKFURT: Frankfurt Stock Exchange\n- SIX: SIX Swiss Exchange\n- MILAN: Milan Stock Exchange\n\nAsia-Pacific:\n- TOKYO: Tokyo Stock Exchange\n- HONG KONG: Hong Kong Stock Exchange\n- SHANGHAI: Shanghai Stock Exchange\n- SHENZHEN: Shenzhen Stock Exchange\n- SGX: Singapore Exchange\n- ASX: Australian Securities Exchange\n- KOREA: Korea Exchange\n- KOSDAQ: KOSDAQ\n\nOther Major Markets:\n- TORONTO: Toronto Stock Exchange\n- TSX VENTURE: TSX Venture Exchange\n- MEXICO: Mexican Stock Exchange\n- SAO PAULO: B3 (Brasil Bolsa Balcão)\n- JOHANNESBURG: Johannesburg Stock Exchange\n\nSpecial Values:\n- NOT LISTED: For unlisted securities\n- OTC US: US Over-the-Counter\n- OTC BB: OTC Bulletin Board\n- PINK SHEETS: Pink Sheets\n\nUsage Example:\n{\n \"idType\": \"ID_EXCH_SYMBOL\",\n \"idValue\": \"AAPL\",\n \"exchCode\": \"US\"\n}\n`\n\n// Security types content (subset of most common)\nconst securityTypesContent = `OpenFIGI Security Types\n======================\n\nCommon Security Types (securityType):\n\nEquity:\n- Common Stock: Common/ordinary shares\n- Preferred: Preferred shares\n- ADR: American Depositary Receipt\n- GDR: Global Depositary Receipt\n- REIT: Real Estate Investment Trust\n- MLP: Master Limited Partnership\n- Right: Rights issue\n- Warrant: Warrant\n- Unit: Unit (combination of securities)\n\nFixed Income:\n- Bond: General bond\n- Conv Bond: Convertible bond\n- COMMERCIAL PAPER: Commercial paper\n- TREASURY BILL: Treasury bill\n- MED TERM NOTE: Medium term note\n\nDerivatives:\n- Equity Option: Stock option\n- Index Option: Index option\n- Currency future.: Currency future\n- Currency option.: Currency option\n\nFunds:\n- Mutual Fund: Mutual fund\n- Open-End Fund: Open-end fund\n- Closed-End Fund: Closed-end fund\n- ETP: Exchange Traded Product\n\nOther:\n- Index: Market index\n- Crypto: Cryptocurrency\n- SWAP: Swap contract\n- FRA: Forward rate agreement\n\nUsage Example:\n{\n \"idType\": \"ID_ISIN\",\n \"idValue\": \"US0378331005\",\n \"securityType\": \"Common Stock\"\n}\n`\n\n// Market sectors content\nconst marketSectorsContent = `OpenFIGI Market Sectors\n======================\n\nMarket Sector Values (marketSecDes):\n\n- Equity: Stocks, shares, and equity derivatives\n- Corp: Corporate bonds and debt instruments\n- Govt: Government bonds and securities\n- Muni: Municipal bonds\n- Mtge: Mortgage-backed securities\n- M-Mkt: Money market instruments\n- Comdty: Commodities\n- Curncy: Currencies and FX instruments\n- Index: Market indices\n- Pfd: Preferred securities\n\nUsage Example:\n{\n \"idType\": \"ID_EXCH_SYMBOL\",\n \"idValue\": \"AAPL\",\n \"marketSecDes\": \"Equity\"\n}\n\nNote: Market sector helps narrow down search results when multiple\nsecurities share the same identifier across different asset classes.\n`\n\nexport function handleResource(uri: string): {\n contents: Array<{\n uri: string\n mimeType: string\n text: string\n }>\n} {\n switch (uri) {\n case 'openfigi://search-guide':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: searchGuideContent,\n },\n ],\n }\n\n case 'openfigi://identifier-types':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: identifierTypesContent,\n },\n ],\n }\n\n case 'openfigi://exchange-codes':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: exchangeCodesContent,\n },\n ],\n }\n\n case 'openfigi://security-types':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: securityTypesContent,\n },\n ],\n }\n\n case 'openfigi://market-sectors':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: marketSectorsContent,\n },\n ],\n }\n\n default:\n throw new Error(`Unknown resource: ${uri}`)\n }\n}\n","import { Server } from '@modelcontextprotocol/sdk/server/index.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport {\n CallToolRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n ReadResourceRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js'\nimport { toolDefinitions, handleTool } from './tools/index.js'\nimport { resourceDefinitions, handleResource } from './resources/index.js'\n\n// Create the MCP server\nconst server = new Server(\n {\n name: 'openfigi-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n },\n }\n)\n\n// Handle tool listing\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: toolDefinitions.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n }\n})\n\n// Handle tool execution\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params\n return handleTool(name, args ?? {})\n})\n\n// Handle resource listing\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resourceDefinitions.map((resource) => ({\n uri: resource.uri,\n name: resource.name,\n description: resource.description,\n mimeType: resource.mimeType,\n })),\n }\n})\n\n// Handle resource reading\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const { uri } = request.params\n return handleResource(uri)\n})\n\n// Start the server\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n console.error('OpenFIGI MCP server running on stdio')\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error)\n process.exit(1)\n})\n"],"mappings":"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iBAAiB;IAC1B,UAAU,iBAAiB;IAC3B,cAAc,iBAAiB;IAC/B,cAAc,iBAAiB;IAC/B,yBAAyB,iBAAiB;GAC3C;GACD,UAAU,CAAC,QAAS;EACrB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aAAa;IACd;IACD,GAAG;GACJ;GACD,UAAU,CAAC,aAAc;EAC1B;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,aAAa;IACX,MAAM;IACN,OAAO;KACL,MAAM;KACN,YAAY;MACV,QAAQ;OACN,MAAM;OACN,aACE;MACH;MACD,SAAS;OACP,MAAM;OACN,aAAa;MACd;MACD,UAAU;OACR,MAAM;OACN,aAAa;MACd;KACF;KACD,UAAU,CAAC,UAAU,SAAU;IAChC;IACD,aAAa;GACd,EACF;GACD,UAAU,CAAC,aAAc;EAC1B;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,YAAY;KACV,MAAM;KACN,aAAa;IACd;IACD,MAAM;KACJ,MAAM;KACN,MAAM;MAAC;MAAQ;MAAS;MAAS;KAAe;KAChD,aAAa;IACd;GACF;GACD,UAAU,CAAC,cAAc,MAAO;EACjC;CACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY,CAAE;EACf;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,MAAM;IACJ,MAAM;IACN,aACE;GACH,EACF;GACD,UAAU,CAAC,MAAO;EACnB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,YAAY;IACV,MAAM;IACN,aACE;GACH,EACF;GACD,UAAU,CAAC,YAAa;EACzB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,MAAM;IACJ,MAAM;IACN,aACE;GACH,EACF;GACD,UAAU,CAAC,MAAO;EACnB;CACF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"}
1
+ {"version":3,"file":"index.js","names":["array: T[]","size: number","chunks: T[][]","args: Record<string, unknown>","identifier: string","text: string","identifiers: DetectedIdentifier[]","typeCounts: Record<IdentifierType, number>","response: MappingResponse","result: FigiResult","index: number","name: string","requests: MappingRequest[]","allResponses: MappingResponse[]","idTypeMap: Record<IdentifierType, MappingRequest['idType']>","found: string[]","notFound: string[]","uri: string"],"sources":["../src/polyfill.ts","../src/tools/index.ts","../src/resources/index.ts","../src/index.ts"],"sourcesContent":["// Polyfill fetch for Node.js < 18\nif (typeof globalThis.fetch === 'undefined') {\n const { fetch, Headers, Request, Response } = await import('undici')\n Object.assign(globalThis, { fetch, Headers, Request, Response })\n}\n\nexport {}\n","import {\n createClient,\n isValidISIN,\n isValidCUSIP,\n isValidSEDOL,\n isValidBloombergId,\n type MappingRequest,\n type MappingResponse,\n type FigiResult,\n} from 'openfigi-sdk'\n\ninterface SearchFilters {\n exchCode?: string\n micCode?: string\n currency?: string\n marketSecDes?: string\n securityType?: string\n includeUnlistedEquities?: boolean\n}\n\n// Common filter properties for JSON schema\nconst filterProperties = {\n exchCode: {\n type: 'string',\n description: 'Exchange code filter (e.g., \"US\", \"NASDAQ\")',\n },\n micCode: {\n type: 'string',\n description: 'MIC code filter (e.g., \"XNAS\", \"XNYS\")',\n },\n currency: {\n type: 'string',\n description: 'Currency filter (e.g., \"USD\", \"EUR\")',\n },\n marketSecDes: {\n type: 'string',\n description: 'Market sector filter (e.g., \"Equity\", \"Corp\")',\n },\n securityType: {\n type: 'string',\n description: 'Security type filter (e.g., \"Common Stock\")',\n },\n includeUnlistedEquities: {\n type: 'boolean',\n description: 'Include unlisted equities',\n },\n} as const\n\n// Create client with API key from environment\nconst getClient = () => {\n const apiKey = process.env.OPENFIGI_API_KEY\n return createClient({ apiKey })\n}\n\n// Check if API key is configured\nconst hasApiKey = () => Boolean(process.env.OPENFIGI_API_KEY)\n\n// Batch size limits based on API key presence\nconst getBatchSize = () => (hasApiKey() ? 100 : 10)\n\n// Helper to chunk array into smaller batches\nconst chunkArray = <T>(array: T[], size: number): T[][] => {\n const chunks: T[][] = []\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size))\n }\n return chunks\n}\n\n// Extract filter properties from args\nconst extractFilters = (args: Record<string, unknown>): SearchFilters => ({\n exchCode: args.exchCode as string | undefined,\n micCode: args.micCode as string | undefined,\n currency: args.currency as string | undefined,\n marketSecDes: args.marketSecDes as string | undefined,\n securityType: args.securityType as string | undefined,\n includeUnlistedEquities: args.includeUnlistedEquities as boolean | undefined,\n})\n\n// Detect identifier type from a string\ntype IdentifierType = 'ISIN' | 'CUSIP' | 'SEDOL' | 'BLOOMBERG_ID' | 'TICKER' | 'UNKNOWN'\n\ninterface DetectedIdentifier {\n value: string\n type: IdentifierType\n exchCode?: string\n confidence: 'high' | 'medium' | 'low'\n}\n\nconst detectIdentifierType = (identifier: string): DetectedIdentifier => {\n const trimmed = identifier.trim()\n\n // Check for ISIN (12 chars, 2 letter country code + 9 alphanumeric + 1 check digit)\n if (isValidISIN(trimmed)) {\n return { value: trimmed, type: 'ISIN', confidence: 'high' }\n }\n\n // Check for Bloomberg ID (starts with BBG)\n if (isValidBloombergId(trimmed)) {\n return { value: trimmed, type: 'BLOOMBERG_ID', confidence: 'high' }\n }\n\n // Check for CUSIP (9 alphanumeric)\n if (isValidCUSIP(trimmed)) {\n return { value: trimmed, type: 'CUSIP', confidence: 'medium' }\n }\n\n // Check for SEDOL (7 alphanumeric)\n if (isValidSEDOL(trimmed)) {\n return { value: trimmed, type: 'SEDOL', confidence: 'medium' }\n }\n\n // Check for ticker with exchange suffix (e.g., \"AAPL US\", \"ABLI SS\")\n const tickerWithExchange = trimmed.match(/^([A-Z0-9]+)\\s+([A-Z]{2})$/i)\n if (tickerWithExchange) {\n return {\n value: tickerWithExchange[1].toUpperCase(),\n type: 'TICKER',\n exchCode: tickerWithExchange[2].toUpperCase(),\n confidence: 'high',\n }\n }\n\n // Check for simple ticker (all caps, 1-5 chars)\n if (/^[A-Z]{1,5}$/.test(trimmed)) {\n return { value: trimmed, type: 'TICKER', confidence: 'low' }\n }\n\n // Check for ticker with numbers (e.g., \"BRK.A\", \"TSLA3\")\n if (/^[A-Z0-9.]{1,10}$/i.test(trimmed)) {\n return { value: trimmed.toUpperCase(), type: 'TICKER', confidence: 'low' }\n }\n\n return { value: trimmed, type: 'UNKNOWN', confidence: 'low' }\n}\n\n// Parse CSV/text data and detect identifiers\nconst parseAndDetectIdentifiers = (\n text: string\n): { identifiers: DetectedIdentifier[]; summary: string } => {\n const lines = text.split(/\\r?\\n/).filter((line) => line.trim())\n const identifiers: DetectedIdentifier[] = []\n const typeCounts: Record<IdentifierType, number> = {\n ISIN: 0,\n CUSIP: 0,\n SEDOL: 0,\n BLOOMBERG_ID: 0,\n TICKER: 0,\n UNKNOWN: 0,\n }\n\n // Check if first line looks like a header\n const firstLine = lines[0]?.trim().toLowerCase()\n const hasHeader =\n firstLine?.includes('ticker') ||\n firstLine?.includes('isin') ||\n firstLine?.includes('cusip') ||\n firstLine?.includes('sedol') ||\n firstLine?.includes('symbol') ||\n firstLine?.includes('identifier')\n\n const dataLines = hasHeader ? lines.slice(1) : lines\n\n for (const line of dataLines) {\n // Handle CSV/tab-separated: take first column\n const columns = line.split(/[,\\t]/)\n const value = columns[0]?.trim()\n\n if (value && value.length > 0) {\n const detected = detectIdentifierType(value)\n identifiers.push(detected)\n typeCounts[detected.type]++\n }\n }\n\n const summary = [\n `Detected ${identifiers.length} identifiers:`,\n typeCounts.ISIN > 0 ? ` - ISIN: ${typeCounts.ISIN}` : null,\n typeCounts.CUSIP > 0 ? ` - CUSIP: ${typeCounts.CUSIP}` : null,\n typeCounts.SEDOL > 0 ? ` - SEDOL: ${typeCounts.SEDOL}` : null,\n typeCounts.BLOOMBERG_ID > 0\n ? ` - Bloomberg ID: ${typeCounts.BLOOMBERG_ID}`\n : null,\n typeCounts.TICKER > 0 ? ` - Ticker: ${typeCounts.TICKER}` : null,\n typeCounts.UNKNOWN > 0 ? ` - Unknown: ${typeCounts.UNKNOWN}` : null,\n ]\n .filter(Boolean)\n .join('\\n')\n\n return { identifiers, summary }\n}\n\n// Format a mapping response for display\nconst formatResponse = (response: MappingResponse): string => {\n if (response.error) {\n return `Error: ${response.error}`\n }\n if (response.warning) {\n return `Warning: ${response.warning}`\n }\n if (!response.data || response.data.length === 0) {\n return 'No results found'\n }\n\n return response.data\n .map((result: FigiResult, index: number) => {\n const lines = [`Result ${index + 1}:`]\n lines.push(` FIGI: ${result.figi}`)\n if (result.name) lines.push(` Name: ${result.name}`)\n if (result.ticker) lines.push(` Ticker: ${result.ticker}`)\n if (result.exchCode) lines.push(` Exchange: ${result.exchCode}`)\n if (result.marketSector) lines.push(` Market Sector: ${result.marketSector}`)\n if (result.securityType) lines.push(` Security Type: ${result.securityType}`)\n if (result.compositeFIGI) lines.push(` Composite FIGI: ${result.compositeFIGI}`)\n if (result.shareClassFIGI) lines.push(` Share Class FIGI: ${result.shareClassFIGI}`)\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\n// Tool definitions\nexport const toolDefinitions = [\n {\n name: 'search_by_isin',\n description:\n 'Search for financial instruments by ISIN (International Securities Identification Number). Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n isin: {\n type: 'string',\n description: 'ISIN to search for (e.g., \"US0378331005\" for Apple)',\n },\n ...filterProperties,\n },\n required: ['isin'],\n },\n },\n {\n name: 'search_by_cusip',\n description:\n 'Search for financial instruments by CUSIP (Committee on Uniform Securities Identification Procedures). Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n cusip: {\n type: 'string',\n description: 'CUSIP to search for (e.g., \"037833100\" for Apple)',\n },\n ...filterProperties,\n },\n required: ['cusip'],\n },\n },\n {\n name: 'search_by_sedol',\n description:\n 'Search for financial instruments by SEDOL (Stock Exchange Daily Official List). Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n sedol: {\n type: 'string',\n description: 'SEDOL to search for (e.g., \"2046251\" for Apple)',\n },\n ...filterProperties,\n },\n required: ['sedol'],\n },\n },\n {\n name: 'search_by_ticker',\n description:\n 'Search for financial instruments by ticker symbol. Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n ticker: {\n type: 'string',\n description: 'Ticker symbol to search for (e.g., \"AAPL\")',\n },\n exchCode: {\n type: 'string',\n description: 'Exchange code to narrow search (e.g., \"US\", \"NASDAQ\")',\n },\n micCode: filterProperties.micCode,\n currency: filterProperties.currency,\n marketSecDes: filterProperties.marketSecDes,\n securityType: filterProperties.securityType,\n includeUnlistedEquities: filterProperties.includeUnlistedEquities,\n },\n required: ['ticker'],\n },\n },\n {\n name: 'search_by_bloomberg_id',\n description:\n 'Search for financial instruments by Bloomberg Global ID. Returns FIGI identifiers and instrument details.',\n inputSchema: {\n type: 'object',\n properties: {\n bloombergId: {\n type: 'string',\n description: 'Bloomberg Global ID to search for (e.g., \"BBG000B9XRY4\")',\n },\n ...filterProperties,\n },\n required: ['bloombergId'],\n },\n },\n {\n name: 'batch_mapping',\n description:\n 'Map multiple financial identifiers to FIGIs in a single request. Supports up to 100 identifiers per request.',\n inputSchema: {\n type: 'object',\n properties: {\n identifiers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n idType: {\n type: 'string',\n description:\n 'Type of identifier (e.g., \"ID_ISIN\", \"ID_CUSIP\", \"ID_SEDOL\", \"ID_EXCH_SYMBOL\", \"ID_BB_GLOBAL\")',\n },\n idValue: {\n type: 'string',\n description: 'The identifier value',\n },\n exchCode: {\n type: 'string',\n description: 'Optional exchange code filter',\n },\n },\n required: ['idType', 'idValue'],\n },\n description: 'Array of identifiers to map (max 100)',\n },\n },\n required: ['identifiers'],\n },\n },\n {\n name: 'validate_identifier',\n description:\n 'Validate the format of a financial identifier (ISIN, CUSIP, SEDOL, or Bloomberg ID).',\n inputSchema: {\n type: 'object',\n properties: {\n identifier: {\n type: 'string',\n description: 'The identifier to validate',\n },\n type: {\n type: 'string',\n enum: ['ISIN', 'CUSIP', 'SEDOL', 'BLOOMBERG_ID'],\n description: 'Type of identifier to validate',\n },\n },\n required: ['identifier', 'type'],\n },\n },\n {\n name: 'get_rate_limit_status',\n description: 'Get the current OpenFIGI API rate limit status.',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'parse_identifiers',\n description:\n 'Parse and auto-detect financial identifiers from CSV/text data. Supports tickers with exchange codes (e.g., \"AAPL US\", \"ABLI SS\"), ISINs, CUSIPs, SEDOLs, and Bloomberg IDs. Automatically detects the identifier type and extracts exchange codes when present.',\n inputSchema: {\n type: 'object',\n properties: {\n text: {\n type: 'string',\n description:\n 'CSV or newline-separated text containing identifiers. Can include headers. Example: \"Ticker\\\\nABLI SS\\\\nACE SS\"',\n },\n },\n required: ['text'],\n },\n },\n {\n name: 'search_auto_detect',\n description:\n 'Automatically detect the identifier type and search for a single financial instrument. Supports ISINs, CUSIPs, SEDOLs, Bloomberg IDs, and tickers with optional exchange codes (e.g., \"AAPL US\").',\n inputSchema: {\n type: 'object',\n properties: {\n identifier: {\n type: 'string',\n description:\n 'The identifier to search for. Type will be auto-detected. Examples: \"US0378331005\" (ISIN), \"037833100\" (CUSIP), \"AAPL US\" (ticker with exchange)',\n },\n },\n required: ['identifier'],\n },\n },\n {\n name: 'batch_search_auto_detect',\n description:\n 'Parse identifiers from text/CSV and search for all of them in a single batch operation. Automatically detects identifier types. Great for processing lists of tickers or identifiers from spreadsheets.',\n inputSchema: {\n type: 'object',\n properties: {\n text: {\n type: 'string',\n description:\n 'CSV or newline-separated text containing identifiers. Example: \"Ticker\\\\nABLI SS\\\\nACE SS\\\\nACTI SS\"',\n },\n },\n required: ['text'],\n },\n },\n] as const\n\n// Tool handlers\nexport async function handleTool(\n name: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: 'text'; text: string }> }> {\n const client = getClient()\n\n try {\n switch (name) {\n case 'search_by_isin': {\n const isin = args.isin as string\n const filters = extractFilters(args)\n const response = await client.searchByISIN(isin, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_cusip': {\n const cusip = args.cusip as string\n const filters = extractFilters(args)\n const response = await client.searchByCUSIP(cusip, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_sedol': {\n const sedol = args.sedol as string\n const filters = extractFilters(args)\n const response = await client.searchBySEDOL(sedol, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_ticker': {\n const ticker = args.ticker as string\n const exchCode = args.exchCode as string | undefined\n const filters = extractFilters(args)\n const response = await client.searchByTicker(ticker, exchCode, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'search_by_bloomberg_id': {\n const bloombergId = args.bloombergId as string\n const filters = extractFilters(args)\n const response = await client.searchByBloombergId(bloombergId, filters)\n return { content: [{ type: 'text', text: formatResponse(response) }] }\n }\n\n case 'batch_mapping': {\n const { identifiers } = args as {\n identifiers: Array<{\n idType: string\n idValue: string\n exchCode?: string\n }>\n }\n\n const requests: MappingRequest[] = identifiers.map((id) => ({\n idType: id.idType as MappingRequest['idType'],\n idValue: id.idValue,\n exchCode: id.exchCode as MappingRequest['exchCode'],\n }))\n\n // Split into batches based on API key presence\n const batchSize = getBatchSize()\n const batches = chunkArray(requests, batchSize)\n\n // Process all batches and combine results\n const allResponses: MappingResponse[] = []\n for (const batch of batches) {\n const batchResponses = await client.mapping(batch)\n allResponses.push(...batchResponses)\n }\n const responses = allResponses\n const formatted = responses\n .map((response: MappingResponse, index: number) => {\n const id = identifiers[index]\n return `[${index + 1}] ${id.idType}: ${id.idValue}\\n${formatResponse(response)}`\n })\n .join('\\n\\n---\\n\\n')\n\n return { content: [{ type: 'text', text: formatted }] }\n }\n\n case 'validate_identifier': {\n const { identifier, type } = args as {\n identifier: string\n type: 'ISIN' | 'CUSIP' | 'SEDOL' | 'BLOOMBERG_ID'\n }\n\n let isValid = false\n let format = ''\n\n switch (type) {\n case 'ISIN':\n isValid = isValidISIN(identifier)\n format = '2 letter country code + 9 alphanumeric characters + 1 check digit'\n break\n case 'CUSIP':\n isValid = isValidCUSIP(identifier)\n format = '9 alphanumeric characters'\n break\n case 'SEDOL':\n isValid = isValidSEDOL(identifier)\n format = '7 alphanumeric characters'\n break\n case 'BLOOMBERG_ID':\n isValid = isValidBloombergId(identifier)\n format = 'BBG + 9 alphanumeric characters'\n break\n }\n\n const result = isValid\n ? `Valid ${type}: \"${identifier}\"`\n : `Invalid ${type}: \"${identifier}\"\\nExpected format: ${format}`\n\n return { content: [{ type: 'text', text: result }] }\n }\n\n case 'get_rate_limit_status': {\n const rateLimit = client.getRateLimitInfo()\n\n if (!rateLimit) {\n return {\n content: [\n {\n type: 'text',\n text: 'No rate limit information available. Make a request first to get rate limit data.',\n },\n ],\n }\n }\n\n const text = [\n 'OpenFIGI API Rate Limit Status:',\n ` Limit: ${rateLimit.limit} requests`,\n ` Remaining: ${rateLimit.remaining} requests`,\n ` Resets: ${rateLimit.reset.toISOString()}`,\n ].join('\\n')\n\n return { content: [{ type: 'text', text }] }\n }\n\n case 'parse_identifiers': {\n const text = args.text as string\n const { identifiers, summary } = parseAndDetectIdentifiers(text)\n\n const details = identifiers\n .map((id, index) => {\n const exchPart = id.exchCode ? ` (Exchange: ${id.exchCode})` : ''\n return `${index + 1}. \"${id.value}\" → ${id.type}${exchPart} [${id.confidence} confidence]`\n })\n .join('\\n')\n\n return {\n content: [\n {\n type: 'text',\n text: `${summary}\\n\\nDetails:\\n${details}`,\n },\n ],\n }\n }\n\n case 'search_auto_detect': {\n const identifier = args.identifier as string\n const detected = detectIdentifierType(identifier)\n\n if (detected.type === 'UNKNOWN') {\n return {\n content: [\n {\n type: 'text',\n text: `Could not determine identifier type for \"${identifier}\". Please use a specific search tool or provide more context.`,\n },\n ],\n }\n }\n\n let response: MappingResponse\n\n switch (detected.type) {\n case 'ISIN':\n response = await client.searchByISIN(detected.value)\n break\n case 'CUSIP':\n response = await client.searchByCUSIP(detected.value)\n break\n case 'SEDOL':\n response = await client.searchBySEDOL(detected.value)\n break\n case 'BLOOMBERG_ID':\n response = await client.searchByBloombergId(detected.value)\n break\n case 'TICKER':\n response = await client.searchByTicker(detected.value, detected.exchCode)\n break\n }\n\n const header = `Detected type: ${detected.type}${detected.exchCode ? ` (Exchange: ${detected.exchCode})` : ''} [${detected.confidence} confidence]\\n\\n`\n const hasResults = response.data && response.data.length > 0\n const notFoundWarning = hasResults ? '' : `⚠️ NOT FOUND: \"${detected.value}\"${detected.exchCode ? ` on exchange ${detected.exchCode}` : ''} returned no results.\\n\\n`\n return { content: [{ type: 'text', text: header + notFoundWarning + formatResponse(response) }] }\n }\n\n case 'batch_search_auto_detect': {\n const text = args.text as string\n const { identifiers, summary } = parseAndDetectIdentifiers(text)\n\n // Filter out unknown identifiers\n const validIdentifiers = identifiers.filter((id) => id.type !== 'UNKNOWN')\n\n if (validIdentifiers.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: `${summary}\\n\\nNo valid identifiers found to search.`,\n },\n ],\n }\n }\n\n // Convert to mapping requests\n const idTypeMap: Record<IdentifierType, MappingRequest['idType']> = {\n ISIN: 'ID_ISIN',\n CUSIP: 'ID_CUSIP',\n SEDOL: 'ID_SEDOL',\n BLOOMBERG_ID: 'ID_BB_GLOBAL',\n TICKER: 'ID_EXCH_SYMBOL',\n UNKNOWN: 'ID_EXCH_SYMBOL', // Won't be used\n }\n\n const requests: MappingRequest[] = validIdentifiers.map((id) => ({\n idType: idTypeMap[id.type],\n idValue: id.value,\n exchCode: id.exchCode as MappingRequest['exchCode'],\n // securityType2 is required for ID_EXCH_SYMBOL (ticker) searches\n ...(id.type === 'TICKER' && { securityType2: 'Common Stock' as const }),\n }))\n\n // Split into batches based on API key presence\n const batchSize = getBatchSize()\n const batches = chunkArray(requests, batchSize)\n\n // Process all batches and combine results\n const allResponses: MappingResponse[] = []\n for (const batch of batches) {\n const batchResponses = await client.mapping(batch)\n allResponses.push(...batchResponses)\n }\n const responses = allResponses\n // Track found and not found\n const found: string[] = []\n const notFound: string[] = []\n\n const formatted = responses\n .map((response: MappingResponse, index: number) => {\n const id = validIdentifiers[index]\n const exchPart = id.exchCode ? ` [${id.exchCode}]` : ''\n const idLabel = `${id.value}${exchPart}`\n\n // Check if no results\n const hasResults = response.data && response.data.length > 0\n if (hasResults) {\n found.push(idLabel)\n } else {\n notFound.push(idLabel)\n }\n\n const status = hasResults ? '' : ' ⚠️ NOT FOUND'\n return `[${index + 1}] ${id.type}: ${idLabel}${status}\\n${formatResponse(response)}`\n })\n .join('\\n\\n---\\n\\n')\n\n // Add summary of found/not found\n const resultSummary = [\n `\\nResults: ${found.length} found, ${notFound.length} not found`,\n notFound.length > 0 ? `\\n⚠️ Not found:\\n${notFound.map((id) => ` - ${id}`).join('\\n')}` : '',\n ].join('')\n\n return { content: [{ type: 'text', text: `${summary}\\n\\n${formatted}\\n\\n---${resultSummary}` }] }\n }\n\n default:\n return {\n content: [{ type: 'text', text: `Unknown tool: ${name}` }],\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return { content: [{ type: 'text', text: `Error: ${message}` }] }\n }\n}\n","// Resource definitions for OpenFIGI MCP server\n// These provide reference data for identifier types, exchange codes, security types, etc.\n\nexport const resourceDefinitions = [\n {\n uri: 'openfigi://search-guide',\n name: 'Search Guide',\n description: 'IMPORTANT: Read this first! Guide on how to effectively search for securities using OpenFIGI',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://identifier-types',\n name: 'Identifier Types',\n description: 'List of supported financial identifier types for OpenFIGI API',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://exchange-codes',\n name: 'Exchange Codes',\n description: 'Common exchange codes used in OpenFIGI API',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://security-types',\n name: 'Security Types',\n description: 'Common security types used in OpenFIGI API',\n mimeType: 'text/plain',\n },\n {\n uri: 'openfigi://market-sectors',\n name: 'Market Sectors',\n description: 'Market sector values used in OpenFIGI API',\n mimeType: 'text/plain',\n },\n] as const\n\n// Search guide content - helps AI understand how to search effectively\nconst searchGuideContent = `OpenFIGI Search Guide\n=====================\n\n## Best Practices for Searching Securities\n\n### 1. PREFER ISIN OVER TICKER\nISINs are globally unique and always return accurate results:\n- ISIN format: 2-letter country code + 9 alphanumeric + 1 check digit\n- Example: US0378331005 (Apple), SE0000108656 (Ericsson)\n- Use search_by_isin for the most reliable results\n\n### 2. TICKER SEARCH REQUIREMENTS\nWhen searching by ticker (search_by_ticker or search_auto_detect):\n- MUST include exchange code for accurate results\n- Uses securityType2=\"Common Stock\" by default\n- Swedish tickers need share class: \"ERIC B\" not \"ERIC\"\n- US tickers: \"AAPL\" with exchCode \"US\"\n\n### 3. EXCHANGE CODE MAPPING\nCommon Bloomberg-style suffixes and their OpenFIGI exchCode:\n- \"SS\" → exchCode: \"SS\" (Stockholm/Nasdaq Nordic)\n- \"US\" → exchCode: \"US\" (United States)\n- \"LN\" → exchCode: \"LONDON\" or \"LSE\"\n- \"GY\" or \"GR\" → exchCode: \"XETRA\" or \"FRANKFURT\"\n- \"FP\" → exchCode: \"EURONEXT-PARIS\"\n- \"NA\" → exchCode: \"EURONEXT-AMSTER\"\n- \"FH\" → exchCode: \"FH\" (Helsinki)\n- \"DC\" → exchCode: \"NOMX COPENHAGEN\"\n- \"NO\" → exchCode: \"OSLO\"\n- \"JP\" → exchCode: \"TOKYO\"\n- \"HK\" → exchCode: \"HONG KONG\"\n\n### 4. NORDIC STOCK TICKER CONVENTIONS\nNordic stocks often have share class suffixes:\n- A shares: \"VOLV A SS\" (Volvo A shares)\n- B shares: \"ERIC B SS\" (Ericsson B shares)\n- Common pattern: TICKER + space + CLASS + space + EXCHANGE\n- If search fails, try adding \"A\" or \"B\" suffix\n\n### 5. HANDLING \"NOT FOUND\" RESULTS\nIf a ticker search returns no results:\n1. Check if share class is needed (add A/B suffix)\n2. Try without exchange code for broader search\n3. Search by ISIN if available (most reliable)\n4. Check if company uses different ticker in OpenFIGI\n\n### 6. BATCH SEARCH TIPS\nFor batch_search_auto_detect:\n- Supports ISINs, tickers with exchange codes, CUSIPs, SEDOLs\n- Format: \"TICKER EXCHANGE\" on each line (e.g., \"AAPL US\")\n- Automatically splits into smaller batches\n- Mix of identifier types is supported\n\n### 7. DATA SOURCE FORMATS\nDifferent data sources format tickers differently:\n\nBloomberg: \"AAPL US Equity\" → use \"AAPL\" with exchCode \"US\"\nFactSet: \"AAPL-US\" → use \"AAPL\" with exchCode \"US\"\nReuters: \"AAPL.O\" → use \"AAPL\" with exchCode \"NASDAQ\"\n\n### 8. WHEN TO USE WHICH TOOL\n- search_by_isin: Best for accuracy, use when ISIN is available\n- search_by_ticker: When you have ticker + exchange\n- search_auto_detect: Single identifier, type unknown\n- batch_search_auto_detect: Multiple identifiers from spreadsheet/CSV\n- search_by_cusip: US securities with CUSIP\n- search_by_sedol: UK/Irish securities with SEDOL\n\n### 9. COMMON PITFALLS\n- Ticker without exchange: May return too many or zero results\n- Wrong exchange code: \"NASDAQ\" vs \"US\" can give different results\n- Missing share class: Nordic stocks often need A/B suffix\n- Case sensitivity: Tickers are converted to uppercase automatically\n`\n\n// Identifier types content\nconst identifierTypesContent = `OpenFIGI Identifier Types\n========================\n\nThe OpenFIGI API supports the following identifier types (idType):\n\nPrimary Identifiers:\n- ID_ISIN: International Securities Identification Number (12 characters, e.g., US0378331005)\n- ID_CUSIP: Committee on Uniform Securities Identification Procedures (9 characters, e.g., 037833100)\n- ID_SEDOL: Stock Exchange Daily Official List (7 characters, e.g., 2046251)\n- ID_EXCH_SYMBOL: Exchange ticker symbol (e.g., AAPL)\n\nBloomberg Identifiers:\n- ID_BB_GLOBAL: Bloomberg Global Identifier (e.g., BBG000B9XRY4)\n- ID_BB: Bloomberg ID\n- ID_BB_UNIQUE: Bloomberg Unique ID\n- ID_BB_SEC_NUM: Bloomberg Security Number\n- ID_BB_SEC_NUM_DES: Bloomberg Security Number Description\n- ID_BB_GLOBAL_SHARE_CLASS_LEVEL: Bloomberg Share Class Level FIGI\n- COMPOSITE_ID_BB_GLOBAL: Bloomberg Composite Global ID\n\nRegional Identifiers:\n- ID_CINS: CUSIP International Numbering System\n- ID_COMMON: Common Code (used in Euroclear/Clearstream)\n- ID_WERTPAPIER: German securities identifier (WKN)\n- ID_BELGIUM: Belgian securities identifier\n- ID_DENMARK: Danish securities identifier (Fondskode)\n- ID_FRANCE: French securities identifier (SICOVAM)\n- ID_ITALY: Italian securities identifier (Codice ABI)\n- ID_JAPAN: Japanese securities identifier\n- ID_LUXEMBOURG: Luxembourg securities identifier\n- ID_NETHERLANDS: Dutch securities identifier\n- ID_POLAND: Polish securities identifier\n- ID_PORTUGAL: Portuguese securities identifier\n- ID_SWEDEN: Swedish securities identifier\n\nOther:\n- ID_FULL_EXCHANGE_SYMBOL: Full exchange symbol including exchange identifier\n- ID_SHORT_CODE: Short code identifier\n\nUsage Example:\n{\n \"idType\": \"ID_ISIN\",\n \"idValue\": \"US0378331005\"\n}\n`\n\n// Exchange codes content (subset of most common)\nconst exchangeCodesContent = `OpenFIGI Exchange Codes\n======================\n\nCommon Exchange Codes (exchCode):\n\nUnited States:\n- US: United States\n- NASDAQ: NASDAQ Stock Exchange\n- NYSE: New York Stock Exchange\n- NYSE AMERICAN: NYSE American (formerly AMEX)\n- NYSE ARCA: NYSE Arca\n- CBOE: Chicago Board Options Exchange\n- CME: Chicago Mercantile Exchange\n\nEurope:\n- LONDON: London Stock Exchange\n- LSE: London Stock Exchange\n- EURONEXT-PARIS: Euronext Paris\n- EURONEXT-AMSTER: Euronext Amsterdam\n- XETRA: Deutsche Börse XETRA\n- FRANKFURT: Frankfurt Stock Exchange\n- SIX: SIX Swiss Exchange\n- MILAN: Milan Stock Exchange\n\nAsia-Pacific:\n- TOKYO: Tokyo Stock Exchange\n- HONG KONG: Hong Kong Stock Exchange\n- SHANGHAI: Shanghai Stock Exchange\n- SHENZHEN: Shenzhen Stock Exchange\n- SGX: Singapore Exchange\n- ASX: Australian Securities Exchange\n- KOREA: Korea Exchange\n- KOSDAQ: KOSDAQ\n\nOther Major Markets:\n- TORONTO: Toronto Stock Exchange\n- TSX VENTURE: TSX Venture Exchange\n- MEXICO: Mexican Stock Exchange\n- SAO PAULO: B3 (Brasil Bolsa Balcão)\n- JOHANNESBURG: Johannesburg Stock Exchange\n\nSpecial Values:\n- NOT LISTED: For unlisted securities\n- OTC US: US Over-the-Counter\n- OTC BB: OTC Bulletin Board\n- PINK SHEETS: Pink Sheets\n\nUsage Example:\n{\n \"idType\": \"ID_EXCH_SYMBOL\",\n \"idValue\": \"AAPL\",\n \"exchCode\": \"US\"\n}\n`\n\n// Security types content (subset of most common)\nconst securityTypesContent = `OpenFIGI Security Types\n======================\n\nCommon Security Types (securityType):\n\nEquity:\n- Common Stock: Common/ordinary shares\n- Preferred: Preferred shares\n- ADR: American Depositary Receipt\n- GDR: Global Depositary Receipt\n- REIT: Real Estate Investment Trust\n- MLP: Master Limited Partnership\n- Right: Rights issue\n- Warrant: Warrant\n- Unit: Unit (combination of securities)\n\nFixed Income:\n- Bond: General bond\n- Conv Bond: Convertible bond\n- COMMERCIAL PAPER: Commercial paper\n- TREASURY BILL: Treasury bill\n- MED TERM NOTE: Medium term note\n\nDerivatives:\n- Equity Option: Stock option\n- Index Option: Index option\n- Currency future.: Currency future\n- Currency option.: Currency option\n\nFunds:\n- Mutual Fund: Mutual fund\n- Open-End Fund: Open-end fund\n- Closed-End Fund: Closed-end fund\n- ETP: Exchange Traded Product\n\nOther:\n- Index: Market index\n- Crypto: Cryptocurrency\n- SWAP: Swap contract\n- FRA: Forward rate agreement\n\nUsage Example:\n{\n \"idType\": \"ID_ISIN\",\n \"idValue\": \"US0378331005\",\n \"securityType\": \"Common Stock\"\n}\n`\n\n// Market sectors content\nconst marketSectorsContent = `OpenFIGI Market Sectors\n======================\n\nMarket Sector Values (marketSecDes):\n\n- Equity: Stocks, shares, and equity derivatives\n- Corp: Corporate bonds and debt instruments\n- Govt: Government bonds and securities\n- Muni: Municipal bonds\n- Mtge: Mortgage-backed securities\n- M-Mkt: Money market instruments\n- Comdty: Commodities\n- Curncy: Currencies and FX instruments\n- Index: Market indices\n- Pfd: Preferred securities\n\nUsage Example:\n{\n \"idType\": \"ID_EXCH_SYMBOL\",\n \"idValue\": \"AAPL\",\n \"marketSecDes\": \"Equity\"\n}\n\nNote: Market sector helps narrow down search results when multiple\nsecurities share the same identifier across different asset classes.\n`\n\nexport function handleResource(uri: string): {\n contents: Array<{\n uri: string\n mimeType: string\n text: string\n }>\n} {\n switch (uri) {\n case 'openfigi://search-guide':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: searchGuideContent,\n },\n ],\n }\n\n case 'openfigi://identifier-types':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: identifierTypesContent,\n },\n ],\n }\n\n case 'openfigi://exchange-codes':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: exchangeCodesContent,\n },\n ],\n }\n\n case 'openfigi://security-types':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: securityTypesContent,\n },\n ],\n }\n\n case 'openfigi://market-sectors':\n return {\n contents: [\n {\n uri,\n mimeType: 'text/plain',\n text: marketSectorsContent,\n },\n ],\n }\n\n default:\n throw new Error(`Unknown resource: ${uri}`)\n }\n}\n","#!/usr/bin/env node\nimport './polyfill.js'\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport {\n CallToolRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n ReadResourceRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js'\nimport { toolDefinitions, handleTool } from './tools/index.js'\nimport { resourceDefinitions, handleResource } from './resources/index.js'\n\n// Create the MCP server\nconst server = new Server(\n {\n name: 'openfigi-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n },\n }\n)\n\n// Handle tool listing\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: toolDefinitions.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n }\n})\n\n// Handle tool execution\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params\n return handleTool(name, args ?? {})\n})\n\n// Handle resource listing\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resourceDefinitions.map((resource) => ({\n uri: resource.uri,\n name: resource.name,\n description: resource.description,\n mimeType: resource.mimeType,\n })),\n }\n})\n\n// Handle resource reading\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const { uri } = request.params\n return handleResource(uri)\n})\n\n// Start the server\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n console.error('OpenFIGI MCP server running on stdio')\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error)\n process.exit(1)\n})\n"],"mappings":";;;;;;;AACA,WAAW,WAAW,UAAU,aAAa;CAC3C,MAAM,EAAE,OAAO,SAAS,SAAS,UAAU,GAAG,MAAM,OAAO;AAC3D,QAAO,OAAO,YAAY;EAAE;EAAO;EAAS;EAAS;CAAU,EAAC;AACjE;;;;ACiBD,MAAM,mBAAmB;CACvB,UAAU;EACR,MAAM;EACN,aAAa;CACd;CACD,SAAS;EACP,MAAM;EACN,aAAa;CACd;CACD,UAAU;EACR,MAAM;EACN,aAAa;CACd;CACD,cAAc;EACZ,MAAM;EACN,aAAa;CACd;CACD,cAAc;EACZ,MAAM;EACN,aAAa;CACd;CACD,yBAAyB;EACvB,MAAM;EACN,aAAa;CACd;AACF;AAGD,MAAM,YAAY,MAAM;CACtB,MAAM,SAAS,QAAQ,IAAI;AAC3B,QAAO,aAAa,EAAE,OAAQ,EAAC;AAChC;AAGD,MAAM,YAAY,MAAM,QAAQ,QAAQ,IAAI,iBAAiB;AAG7D,MAAM,eAAe,MAAO,WAAW,GAAG,MAAM;AAGhD,MAAM,aAAa,CAAIA,OAAYC,SAAwB;CACzD,MAAMC,SAAgB,CAAE;AACxB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,KACrC,QAAO,KAAK,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC;AAEvC,QAAO;AACR;AAGD,MAAM,iBAAiB,CAACC,UAAkD;CACxE,UAAU,KAAK;CACf,SAAS,KAAK;CACd,UAAU,KAAK;CACf,cAAc,KAAK;CACnB,cAAc,KAAK;CACnB,yBAAyB,KAAK;AAC/B;AAYD,MAAM,uBAAuB,CAACC,eAA2C;CACvE,MAAM,UAAU,WAAW,MAAM;AAGjC,KAAI,YAAY,QAAQ,CACtB,QAAO;EAAE,OAAO;EAAS,MAAM;EAAQ,YAAY;CAAQ;AAI7D,KAAI,mBAAmB,QAAQ,CAC7B,QAAO;EAAE,OAAO;EAAS,MAAM;EAAgB,YAAY;CAAQ;AAIrE,KAAI,aAAa,QAAQ,CACvB,QAAO;EAAE,OAAO;EAAS,MAAM;EAAS,YAAY;CAAU;AAIhE,KAAI,aAAa,QAAQ,CACvB,QAAO;EAAE,OAAO;EAAS,MAAM;EAAS,YAAY;CAAU;CAIhE,MAAM,qBAAqB,QAAQ,MAAM,8BAA8B;AACvE,KAAI,mBACF,QAAO;EACL,OAAO,mBAAmB,GAAG,aAAa;EAC1C,MAAM;EACN,UAAU,mBAAmB,GAAG,aAAa;EAC7C,YAAY;CACb;AAIH,KAAI,eAAe,KAAK,QAAQ,CAC9B,QAAO;EAAE,OAAO;EAAS,MAAM;EAAU,YAAY;CAAO;AAI9D,KAAI,qBAAqB,KAAK,QAAQ,CACpC,QAAO;EAAE,OAAO,QAAQ,aAAa;EAAE,MAAM;EAAU,YAAY;CAAO;AAG5E,QAAO;EAAE,OAAO;EAAS,MAAM;EAAW,YAAY;CAAO;AAC9D;AAGD,MAAM,4BAA4B,CAChCC,SAC2D;CAC3D,MAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC;CAC/D,MAAMC,cAAoC,CAAE;CAC5C,MAAMC,aAA6C;EACjD,MAAM;EACN,OAAO;EACP,OAAO;EACP,cAAc;EACd,QAAQ;EACR,SAAS;CACV;CAGD,MAAM,YAAY,MAAM,IAAI,MAAM,CAAC,aAAa;CAChD,MAAM,YACJ,WAAW,SAAS,SAAS,IAC7B,WAAW,SAAS,OAAO,IAC3B,WAAW,SAAS,QAAQ,IAC5B,WAAW,SAAS,QAAQ,IAC5B,WAAW,SAAS,SAAS,IAC7B,WAAW,SAAS,aAAa;CAEnC,MAAM,YAAY,YAAY,MAAM,MAAM,EAAE,GAAG;AAE/C,MAAK,MAAM,QAAQ,WAAW;EAE5B,MAAM,UAAU,KAAK,MAAM,QAAQ;EACnC,MAAM,QAAQ,QAAQ,IAAI,MAAM;AAEhC,MAAI,SAAS,MAAM,SAAS,GAAG;GAC7B,MAAM,WAAW,qBAAqB,MAAM;AAC5C,eAAY,KAAK,SAAS;AAC1B,cAAW,SAAS;EACrB;CACF;CAED,MAAM,UAAU;GACb,WAAW,YAAY,OAAO;EAC/B,WAAW,OAAO,KAAK,YAAY,WAAW,KAAK,IAAI;EACvD,WAAW,QAAQ,KAAK,aAAa,WAAW,MAAM,IAAI;EAC1D,WAAW,QAAQ,KAAK,aAAa,WAAW,MAAM,IAAI;EAC1D,WAAW,eAAe,KACrB,oBAAoB,WAAW,aAAa,IAC7C;EACJ,WAAW,SAAS,KAAK,cAAc,WAAW,OAAO,IAAI;EAC7D,WAAW,UAAU,KAAK,eAAe,WAAW,QAAQ,IAAI;CACjE,EACE,OAAO,QAAQ,CACf,KAAK,KAAK;AAEb,QAAO;EAAE;EAAa;CAAS;AAChC;AAGD,MAAM,iBAAiB,CAACC,aAAsC;AAC5D,KAAI,SAAS,MACX,SAAQ,SAAS,SAAS,MAAM;AAElC,KAAI,SAAS,QACX,SAAQ,WAAW,SAAS,QAAQ;AAEtC,MAAK,SAAS,QAAQ,SAAS,KAAK,WAAW,EAC7C,QAAO;AAGT,QAAO,SAAS,KACb,IAAI,CAACC,QAAoBC,UAAkB;EAC1C,MAAM,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAAG;AACtC,QAAM,MAAM,UAAU,OAAO,KAAK,EAAE;AACpC,MAAI,OAAO,KAAM,OAAM,MAAM,UAAU,OAAO,KAAK,EAAE;AACrD,MAAI,OAAO,OAAQ,OAAM,MAAM,YAAY,OAAO,OAAO,EAAE;AAC3D,MAAI,OAAO,SAAU,OAAM,MAAM,cAAc,OAAO,SAAS,EAAE;AACjE,MAAI,OAAO,aAAc,OAAM,MAAM,mBAAmB,OAAO,aAAa,EAAE;AAC9E,MAAI,OAAO,aAAc,OAAM,MAAM,mBAAmB,OAAO,aAAa,EAAE;AAC9E,MAAI,OAAO,cAAe,OAAM,MAAM,oBAAoB,OAAO,cAAc,EAAE;AACjF,MAAI,OAAO,eAAgB,OAAM,MAAM,sBAAsB,OAAO,eAAe,EAAE;AACrF,SAAO,MAAM,KAAK,KAAK;CACxB,EAAC,CACD,KAAK,OAAO;AAChB;AAGD,MAAa,kBAAkB;CAC7B;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KACJ,MAAM;KACN,aAAa;IACd;IACD,GAAG;GACJ;GACD,UAAU,CAAC,MAAO;EACnB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,OAAO;KACL,MAAM;KACN,aAAa;IACd;IACD,GAAG;GACJ;GACD,UAAU,CAAC,OAAQ;EACpB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,OAAO;KACL,MAAM;KACN,aAAa;IACd;IACD,GAAG;GACJ;GACD,UAAU,CAAC,OAAQ;EACpB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,QAAQ;KACN,MAAM;KACN,aAAa;IACd;IACD,UAAU;KACR,MAAM;KACN,aAAa;IACd;IACD,SAAS,iBAAiB;IAC1B,UAAU,iBAAiB;IAC3B,cAAc,iBAAiB;IAC/B,cAAc,iBAAiB;IAC/B,yBAAyB,iBAAiB;GAC3C;GACD,UAAU,CAAC,QAAS;EACrB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aAAa;IACd;IACD,GAAG;GACJ;GACD,UAAU,CAAC,aAAc;EAC1B;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,aAAa;IACX,MAAM;IACN,OAAO;KACL,MAAM;KACN,YAAY;MACV,QAAQ;OACN,MAAM;OACN,aACE;MACH;MACD,SAAS;OACP,MAAM;OACN,aAAa;MACd;MACD,UAAU;OACR,MAAM;OACN,aAAa;MACd;KACF;KACD,UAAU,CAAC,UAAU,SAAU;IAChC;IACD,aAAa;GACd,EACF;GACD,UAAU,CAAC,aAAc;EAC1B;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,YAAY;KACV,MAAM;KACN,aAAa;IACd;IACD,MAAM;KACJ,MAAM;KACN,MAAM;MAAC;MAAQ;MAAS;MAAS;KAAe;KAChD,aAAa;IACd;GACF;GACD,UAAU,CAAC,cAAc,MAAO;EACjC;CACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY,CAAE;EACf;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,MAAM;IACJ,MAAM;IACN,aACE;GACH,EACF;GACD,UAAU,CAAC,MAAO;EACnB;CACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,YAAY;IACV,MAAM;IACN,aACE;GACH,EACF;GACD,UAAU,CAAC,YAAa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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openfigi-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "MCP server for OpenFIGI API - Map financial identifiers to FIGIs via Model Context Protocol",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,7 +60,7 @@
60
60
  "homepage": "https://github.com/viktorlarsson/openfigi#readme",
61
61
  "funding": "https://github.com/sponsors/viktorlarsson",
62
62
  "engines": {
63
- "node": ">=18.0.0"
63
+ "node": ">=16.0.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@types/node": "^25.0.9",
@@ -74,6 +74,7 @@
74
74
  },
75
75
  "dependencies": {
76
76
  "@modelcontextprotocol/sdk": "^1.12.1",
77
- "openfigi-sdk": "1.2.0"
77
+ "openfigi-sdk": "1.2.0",
78
+ "undici": "^5.29.0"
78
79
  }
79
80
  }