Skip to main content
Glama

show_ordinals

Fetch and display Bitcoin Ordinals inscription data, saving image files locally for further analysis. Essential first step in a structured two-response workflow for processing inscriptions.

Instructions

πŸ”Ή Bitcoin Ordinals Expert Assistant

πŸš€ MANDATORY TWO-RESPONSE PROCESS FOR IMAGES

I strictly follow a two-step structured workflow for processing Bitcoin Ordinal inscriptions. STRICT ADHERENCE IS REQUIRED.


πŸ“Œ Required Tools & Workflow

πŸ” Tools Used:

1️⃣ show_ordinals

  • Fetches inscription data.

  • If the inscription is an image, it MUST:

    • Save it locally and return the local_file_path.

    • (Code currently does NOT return a separate displayable source, only the local path)

2️⃣ image_processor

  • MUST be used for extracting textual/visual data from the image.

  • Takes local_file_path as input.


πŸš€ MANDATORY TWO-STEP RESPONSE WORKFLOW (FOR IMAGES)

πŸ“Œ RESPONSE 1: Display Attempt + Technical Details (NON-TERMINAL)

βœ” Execute
βœ” Return an using the local_file_path as the src attribute. βœ” Follow with detailed technical metadata.
βœ” STOP HERE. NO ANALYSIS YET.

βœ… RESPONSE FORMAT (STRICTLY ENFORCED):

<!-- Attempting display using local path. Note: May not render in standard browsers due to security restrictions. --> <img src="[local_file_path from show_ordinals]" alt="Ordinal Image Inscription" style="max-width: 100%; height: auto;" /> ### πŸ“Š Technical Details * **MIME Type:** [MIME type] * **Size:** [Size] * **Transaction ID:** [Tx ID] * **Status:** [Status] * **Inscription Input:** [Input] * **Local Path (for analysis):** `[local_file_path from show_ordinals]` * [Other available details]

πŸ”Ή End FIRST response here. No OCR, No AI-generated descriptions. This response is intended to be NON-TERMINAL to allow for Step 2.


πŸ“Œ RESPONSE 2: OCR & Content Analysis (Using Designated Tools ONLY)

βœ” AFTER Response 1, consult available tools. βœ” Execute βœ” Strictly use ONLY tool-generated analysis.
βœ” If BOTH tools fail, state failure explicitly.
βœ” Return a new markdown response with the extracted data.

βœ… RESPONSE FORMAT (STRICTLY ENFORCED):

### πŸ“ Detailed Image Analysis (Result from '[Executed Tool Name]') [Extracted OCR text, visual description, or failure message from the tool ONLY]

⚠ No hallucinations. No AI-generated assumptions.


πŸ“Œ FALLBACK MECHANISM (IF OCR TOOLS FAIL)

  • If BOTH image_processor AND vision fail, use a verified fallback OCR tool (if available).

  • If no fallback exists, explicitly state failure instead of hallucinating content.


🎯 Summary: Strict 2-Response Workflow

βœ… Step 1: Execute β†’ Attempt Image Display (using local path) + Metadata. (Response intended as Non-Terminal) βœ… Step 2: Execute β†’ Analysis Description. (Separate Response)


πŸ’‘ This ensures clarity, prevents AI hallucinations, and provides structured responses. πŸš€

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
content_type_filterNoOptional. Filter inscriptions by content type, e.g., 'image/png', 'text/plain', 'application/json'.
inscription_indexNoOptional. The specific index (starting from 0) of the inscription to retrieve within the transaction, if there are multiple.
txidYesThe unique 64-character hexadecimal identifier of the Bitcoin transaction to inspect for Ordinals. Example: 'f1d2d3...a8b9c0'.

Implementation Reference

  • Primary handler for 'show_ordinals' tool call. Validates input, delegates to OrdinalsClient.decodeWitness with 'file' option for image handling, processes images by saving to local path and generating HTML img tag response, formats non-image content (JSON/text).
    protected async handleDecodeWitness(args: unknown) { const result = DecodeWitnessSchema.safeParse(args); if (!result.success) { throw new McpError( ErrorCode.InvalidParams, `Invalid parameters: ${result.error.message}` ); } const txid = result.data.txid; logger.info(`Processing Ordinals for transaction: ${txid}`); try { // Call decodeWitness method with file option to store images in ~/.cache const decodedWitness = await this.client.decodeWitness(txid, "file"); // Check if an image is present in the results // Image paths now never have file:// prefix const images = decodedWitness.filter(content => content.startsWith('data:image/') || (content.length > 0 && !content.startsWith('{') && !content.startsWith('[')) ); // If we have an image, process it for display if (images.length > 0) { const imageData = images[0]; const txInfo = await this.client.getTransaction(txid, false); // Mark this txid as successfully decoded BEFORE processing the image // to avoid timing issues with get_transaction call this.markSuccessfulDecoding(txid); logger.info(`Transaction ${txid} marked as successfully decoded before image processing`); // Use processAndSaveImage method for display return await this.processAndSaveImage(imageData, txid, txInfo); } // For other content types (JSON, text, etc.) const formattedContent = decodedWitness.map(content => { if (content.startsWith('{') || content.startsWith('[')) { try { const jsonData = JSON.parse(content); return `\`\`\`json\n${JSON.stringify(jsonData, null, 2)}\n\`\`\``; } catch (e) { return content; } } return content; }).join('\n\n'); return { content: [ { type: "text", text: formattedContent } ] as TextContent[], }; } catch (error) { // In case of error during the decoding process logger.error({ error }, `Error decoding Ordinals for ${txid}`); return { content: [ { type: "text", text: `Error decoding Ordinals for transaction ${txid}:\n` + `${error instanceof Error ? error.message : String(error)}\n\n` + "This may be due to a blockchain API access issue, an unsupported transaction format, " + "or the transaction may not exist." } ] as TextContent[], }; } }
  • Registers the 'show_ordinals' tool with the MCP server in listToolsRequestHandler, including detailed workflow instructions for image handling and input schema.
    { name: "show_ordinals", description: "## πŸ”Ή Bitcoin Ordinals Expert Assistant \n\n### **πŸš€ MANDATORY TWO-RESPONSE PROCESS FOR IMAGES** \nI strictly follow a **two-step structured workflow** for processing Bitcoin Ordinal inscriptions. **STRICT ADHERENCE IS REQUIRED.** \n\n---\n\n## πŸ“Œ **Required Tools & Workflow** \n\n### **πŸ” Tools Used:** \n1️⃣ **`show_ordinals` (MANDATORY FIRST STEP)** \n - Fetches **inscription data**. \n - If the inscription is an **image**, it **MUST**: \n - **Save it locally** and return the **`local_file_path`**.\n - *(Code currently does NOT return a separate displayable source, only the local path)*\n\n2️⃣ **`image_processor` / `vision` (OCR & Visual Analysis ONLY)** \n - **MUST be used** for extracting textual/visual data from the image.\n - Takes **`local_file_path`** as input.\n\n---\n\n## **πŸš€ MANDATORY TWO-STEP RESPONSE WORKFLOW (FOR IMAGES)** \n\n### **πŸ“Œ RESPONSE 1: Display Attempt + Technical Details (NON-TERMINAL)** \nβœ” **Execute `show_ordinals` FIRST.** \nβœ” **Return an `<img>` tag** using the **`local_file_path` provided by `show_ordinals`** as the `src` attribute.\nβœ” **Follow with detailed technical metadata.** \nβœ” **STOP HERE. NO ANALYSIS YET.** \n\n**βœ… RESPONSE FORMAT (STRICTLY ENFORCED):** \n```html\n<!-- Attempting display using local path. Note: May not render in standard browsers due to security restrictions. -->\n<img src=\"[local_file_path from show_ordinals]\" alt=\"Ordinal Image Inscription\" style=\"max-width: 100%; height: auto;\" />\n\n### πŸ“Š Technical Details \n* **MIME Type:** [MIME type]\n* **Size:** [Size]\n* **Transaction ID:** [Tx ID]\n* **Status:** [Status]\n* **Inscription Input:** [Input]\n* **Local Path (for analysis):** `[local_file_path from show_ordinals]`\n* [Other available details]\n``` \nπŸ”Ή **End FIRST response here.** **No OCR, No AI-generated descriptions. This response is intended to be NON-TERMINAL to allow for Step 2.** \n\n---\n\n### **πŸ“Œ RESPONSE 2: OCR & Content Analysis (Using Designated Tools ONLY)** \nβœ” **AFTER Response 1, consult available tools.**\nβœ” **Execute `image_processor` OR `vision` using the `local_file_path` from Response 1.**\nβœ” **Strictly use ONLY tool-generated analysis.** \nβœ” **If BOTH tools fail, state failure explicitly.** \nβœ” **Return a new markdown response with the extracted data.** \n\n**βœ… RESPONSE FORMAT (STRICTLY ENFORCED):** \n```markdown\n### πŸ“ Detailed Image Analysis (Result from '[Executed Tool Name]')\n\n[Extracted OCR text, visual description, or failure message from the tool ONLY]\n```\n⚠ **No hallucinations. No AI-generated assumptions.** \n\n---\n\n### **πŸ“Œ FALLBACK MECHANISM (IF OCR TOOLS FAIL)** \n- If **BOTH** `image_processor` AND `vision` **fail**, use a **verified fallback OCR tool** (if available).\n- If **no fallback exists**, explicitly **state failure** instead of hallucinating content.\n\n---\n\n### **🎯 Summary: Strict 2-Response Workflow** \nβœ… **Step 1:** **Execute `show_ordinals`** β†’ Attempt Image Display (using local path) + Metadata. (Response intended as Non-Terminal)\nβœ… **Step 2:** **Execute `image_processor` / `vision`** β†’ Analysis Description. (Separate Response)\n\n---\n\nπŸ’‘ **This ensures clarity, prevents AI hallucinations, and provides structured responses.** πŸš€", inputSchema: { type: "object", properties: { txid: { type: "string", description: "The unique 64-character hexadecimal identifier of the Bitcoin transaction to inspect for Ordinals. Example: 'f1d2d3...a8b9c0'." }, inscription_index: { type: "integer", description: "Optional. The specific index (starting from 0) of the inscription to retrieve within the transaction, if there are multiple." }, content_type_filter: { type: "string", description: "Optional. Filter inscriptions by content type, e.g., 'image/png', 'text/plain', 'application/json'." } }, required: ["txid"] } } as Tool, ], }));
  • Zod schema used for input validation in the show_ordinals handler (note: registration schema has additional optional fields not validated here).
    // Schema for decoding witness with image formatting option export const DecodeWitnessSchema = z.object({ txid: z.string().length(64, "Invalid transaction ID"), formatImageOption: z.enum(["base64", "file"]).optional().default("base64"), });
  • Delegated core implementation: extracts all Ordinal inscriptions from tx witness data using extractOrdinalContent/extractAllOrdinals, formats content per type (saves images to ~/.cache/mcp-inscription/ if 'file', base64 otherwise; parses JSON/text), returns formatted strings/paths.
    async decodeWitness(txid: string, formatImageOption: FormatImageOption = "base64"): Promise<string[]> { try { logger.debug(`Decoding witness (Ordinals) for transaction: ${txid}, formatImageOption=${formatImageOption}`); // Check the cache first const cached = this.transactionCache.get(txid); let extractedOrdinals: ExtractedOrdinal[] = []; if (cached) { logger.debug(`Using cached ordinals data for tx ${txid}`); extractedOrdinals = cached.extractedOrdinals; } else { // If not in cache, we need to retrieve the transaction first // getTransaction will extract all inscriptions and put them in cache await this.getTransaction(txid, false); // Now we can get the data from the cache const newCached = this.transactionCache.get(txid); if (newCached) { extractedOrdinals = newCached.extractedOrdinals; } else { logger.warn(`Transaction ${txid} not found in cache after getTransaction call`); } } // Format and return the found inscriptions const decodedData: string[] = []; if (extractedOrdinals.length === 0) { logger.info(`No Ordinal inscriptions found in transaction ${txid}`); return decodedData; } // Convert each extracted inscription to the requested format extractedOrdinals.forEach((ordinal, index) => { const formattedContent = this.formatInscriptionContent( ordinal.contentType, ordinal.content, formatImageOption, txid, index ); if (formattedContent) { decodedData.push(formattedContent); } }); logger.info(`Successfully decoded ${decodedData.length} ordinal inscription(s) from tx ${txid}`); return decodedData; } catch (error: unknown) { logger.error({ error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, txid }, "Failed to decode witness data"); if (error instanceof BitcoinError) throw error; throw handleBlockchainError(error, "Witness Data Decode", txid); } }
  • Key utility to parse Ordinal inscription envelope from witness script buffer and extract raw contentType and data buffer.
    private extractOrdinalContent(scriptBuffer: Buffer): { contentType: string; content: Buffer } | null { try { const decompiled = bitcoin.script.decompile(scriptBuffer); if (!decompiled) { return null; } const ifIndex = decompiled.findIndex((op) => op === bitcoin.opcodes.OP_IF); if (ifIndex === -1 || ifIndex === 0 || decompiled[ifIndex - 1] !== bitcoin.opcodes.OP_FALSE) { return null; } const endifIndex = decompiled.findIndex((op, idx) => idx > ifIndex && op === bitcoin.opcodes.OP_ENDIF); if (endifIndex === -1) { return null; } const ordPushIndex = decompiled.findIndex((op, idx) => idx > ifIndex && idx < endifIndex && isBuffer(op) && op.toString() === 'ord'); if (ordPushIndex === -1) { return null; } let contentTypeIndex = -1; let contentType: string | null = null; if (ordPushIndex + 1 < endifIndex && (decompiled[ordPushIndex + 1] === bitcoin.opcodes.OP_1 || decompiled[ordPushIndex + 1] === 1)) { if (ordPushIndex + 2 < endifIndex && isBuffer(decompiled[ordPushIndex + 2])) { contentTypeIndex = ordPushIndex + 2; contentType = (decompiled[contentTypeIndex] as Buffer).toString('utf8'); } } else { if (ordPushIndex + 1 < endifIndex && isBuffer(decompiled[ordPushIndex + 1])) { contentTypeIndex = ordPushIndex + 1; contentType = (decompiled[contentTypeIndex] as Buffer).toString('utf8'); } } if (contentTypeIndex === -1 || !contentType) { return null; } let separatorIndex = -1; if (contentTypeIndex + 1 < endifIndex) { const nextOp = decompiled[contentTypeIndex + 1]; if (nextOp === bitcoin.opcodes.OP_0) { separatorIndex = contentTypeIndex + 1; } else if (isBuffer(nextOp) && nextOp.length === 1 && nextOp[0] === 0) { separatorIndex = contentTypeIndex + 1; } } if (separatorIndex === -1) { return null; } const dataChunks: Buffer[] = []; for (let i = separatorIndex + 1; i < endifIndex; i++) { const op = decompiled[i]; if (isBuffer(op)) { dataChunks.push(op); } else { logger.warn(`Unexpected opcode ${bitcoin.script.toASM([op])} found within data section at index ${i}.`); } } const fullContent = Buffer.concat(dataChunks); logger.info(`Successfully extracted inscription: Type=${contentType}, Content Size=${fullContent.length}`); return { contentType, content: fullContent }; } catch (error: unknown) { if (error instanceof Error) { logger.error({ error: error.message, stack: error.stack, bufferHex: scriptBuffer.toString('hex') }, "Error during ordinal content extraction"); } else { logger.error({ error: String(error), bufferHex: scriptBuffer.toString('hex') }, "Unknown error during ordinal content extraction"); } return null; }

Other Tools

Related 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/Laz1mov/mcp-inscription'

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