Skip to main content
Glama
marianfoo

SAP Documentation MCP Server

sap_help_get

Retrieve complete SAP Help Portal page content using exact result IDs from search results to access detailed documentation and metadata.

Instructions

GET SAP HELP PAGE: sap_help_get(result_id="sap-help-12345abc")

FUNCTION NAME: sap_help_get (or mcp_sap-docs-remote_sap_help_get)

RETRIEVES: Complete SAP Help Portal page content REQUIRES: Exact result_id from sap_help_search

USAGE PATTERN:

  1. Get ID from sap_help_search results

  2. Use exact ID (don't modify the format)

  3. Receive full page content + metadata

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
result_idYesExact ID from sap_help_search results. Copy the ID exactly as returned.

Implementation Reference

  • Core handler function that implements the sap_help_get tool logic: extracts loio from result_id, fetches metadata and page content from SAP Help private APIs, converts HTML to markdown text, adds metadata, and truncates if necessary.
    export async function getSapHelpContent(resultId: string): Promise<string> {
      try {
        // Extract loio from the result ID
        const loio = resultId.replace('sap-help-', '');
        if (!loio || loio === resultId) {
          throw new Error("Invalid SAP Help result ID. Use an ID from sap_help_search results.");
        }
    
        // First try to get from cache
        const cache = global.sapHelpSearchCache || new Map();
        let hit = cache.get(loio);
    
        if (!hit) {
          // If not in cache, search again to get the full hit data
          const searchParams = {
            transtype: "standard,html,pdf,others", 
            state: "PRODUCTION,TEST,DRAFT",
            product: "",
            version: "",
            q: loio, // Search by loio to find the specific document
            to: "19",
            area: "content",
            advancedSearch: "0",
            excludeNotSearchable: "1",
            language: "en-US",
          };
    
          const searchUrl = `${BASE}/http.svc/elasticsearch?${toQuery(searchParams)}`;
          const searchResponse = await fetch(searchUrl, {
            headers: {
              Accept: "application/json",
              "User-Agent": "mcp-sap-docs/help-get",
              Referer: BASE,
            },
          });
    
          if (!searchResponse.ok) {
            throw new Error(`Failed to find document: ${searchResponse.status} ${searchResponse.statusText}`);
          }
    
          const searchData: SapHelpSearchResponse = await searchResponse.json();
          const results = searchData?.data?.results || [];
          hit = results.find(r => r.loio === loio);
    
          if (!hit) {
            throw new Error(`Document with loio ${loio} not found`);
          }
        }
    
        // Prepare metadata request parameters
        const topic_url = `${hit.loio}.html`;
        let product_url = hit.productId;
        let deliverable_url;
    
        try {
          const { productUrlSeg, deliverableLoio } = parseDocsPathParts(hit.url);
          deliverable_url = deliverableLoio;
          if (!product_url) product_url = productUrlSeg;
        } catch (e) {
          if (!product_url) {
            throw new Error("Could not determine product_url from hit; missing productId and unparsable url");
          }
        }
    
        const language = hit.language || "en-US";
    
        // Get deliverable metadata
        const metadataParams = {
          product_url,
          topic_url,
          version: "LATEST",
          loadlandingpageontopicnotfound: "true",
          deliverable_url,
          language,
          deliverableInfo: "1",
          toc: "1",
        };
    
        const metadataUrl = `${BASE}/http.svc/deliverableMetadata?${toQuery(metadataParams)}`;
        const metadataResponse = await fetch(metadataUrl, {
          headers: {
            Accept: "application/json",
            "User-Agent": "mcp-sap-docs/help-metadata",
            Referer: BASE,
          },
        });
    
        if (!metadataResponse.ok) {
          throw new Error(`Metadata request failed: ${metadataResponse.status} ${metadataResponse.statusText}`);
        }
    
        const metadataData: SapHelpMetadataResponse = await metadataResponse.json();
        const deliverable_id = metadataData?.data?.deliverable?.id;
        const buildNo = metadataData?.data?.deliverable?.buildNo;
        const file_path = metadataData?.data?.filePath || topic_url;
    
        if (!deliverable_id || !buildNo || !file_path) {
          throw new Error("Missing required metadata: deliverable_id, buildNo, or file_path");
        }
    
        // Get page content
        const pageParams = {
          deliverableInfo: "1",
          deliverable_id,
          buildNo,
          file_path,
        };
    
        const pageUrl = `${BASE}/http.svc/pagecontent?${toQuery(pageParams)}`;
        const pageResponse = await fetch(pageUrl, {
          headers: {
            Accept: "application/json",
            "User-Agent": "mcp-sap-docs/help-content",
            Referer: BASE,
          },
        });
    
        if (!pageResponse.ok) {
          throw new Error(`Page content request failed: ${pageResponse.status} ${pageResponse.statusText}`);
        }
    
        const pageData: SapHelpPageContentResponse = await pageResponse.json();
        const title = pageData?.data?.currentPage?.t || pageData?.data?.deliverable?.title || hit.title;
        const bodyHtml = pageData?.data?.body || "";
    
        if (!bodyHtml) {
          return `# ${title}\n\nNo content available for this page.`;
        }
    
        // Convert HTML to readable text while preserving structure
        const cleanText = bodyHtml
          .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') // Remove scripts
          .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '') // Remove styles
          .replace(/<h([1-6])[^>]*>/gi, (_, level) => '\n' + '#'.repeat(parseInt(level)) + ' ') // Convert headings
          .replace(/<\/h[1-6]>/gi, '\n') // Close headings
          .replace(/<p[^>]*>/gi, '\n') // Paragraphs
          .replace(/<\/p>/gi, '\n')
          .replace(/<br[^>]*>/gi, '\n') // Line breaks
          .replace(/<li[^>]*>/gi, '• ') // List items
          .replace(/<\/li>/gi, '\n')
          .replace(/<code[^>]*>/gi, '`') // Inline code
          .replace(/<\/code>/gi, '`')
          .replace(/<pre[^>]*>/gi, '\n```\n') // Code blocks
          .replace(/<\/pre>/gi, '\n```\n')
          .replace(/<[^>]+>/g, '') // Remove remaining HTML tags
          .replace(/\s*\n\s*\n\s*/g, '\n\n') // Clean up multiple newlines
          .replace(/^\s+|\s+$/g, '') // Trim
          .trim();
    
        // Build the full content with metadata
        const fullContent = `# ${title}
    
    **Source:** SAP Help Portal
    **URL:** ${ensureAbsoluteUrl(hit.url)}
    **Product:** ${hit.product || hit.productId || "Unknown"}
    **Version:** ${hit.version || hit.versionId || "Latest"}
    **Language:** ${hit.language || "en-US"}
    ${hit.snippet ? `**Summary:** ${hit.snippet}` : ''}
    
    ---
    
    ${cleanText}
    
    ---
    
    *This content is from the SAP Help Portal and represents official SAP documentation.*`;
    
        // Apply intelligent truncation if content is too large
        const truncationResult = truncateContent(fullContent);
        
        return truncationResult.content;
    
      } catch (error: any) {
        throw new Error(`Failed to get SAP Help content: ${error.message}`);
      }
    }
  • Dispatch logic within the MCP CallToolRequestSchema handler that invokes getSapHelpContent when the tool name is 'sap_help_get', handles logging, error wrapping, and formats the response using createDocumentResponse.
    if (name === "sap_help_get") {
      const { result_id } = args as { result_id: string };
      
      // Enhanced logging with timing
      const timing = logger.logToolStart(name, result_id, clientMetadata);
      
      try {
        const content = await getSapHelpContent(result_id);
        
        // Transform SAP Help content to structured format
        const document: DocumentResult = {
          id: result_id,
          title: `SAP Help Document (${result_id})`,
          text: content,
          url: `https://help.sap.com/#${result_id}`,
          metadata: {
            source: 'sap-help',
            resultId: result_id,
            contentLength: content.length
          }
        };
        
        logger.logToolSuccess(name, timing.requestId, timing.startTime, 1, { 
          contentLength: content.length,
          resultId: result_id
        });
        
        return createDocumentResponse(document);
      } catch (error) {
        logger.logToolError(name, timing.requestId, timing.startTime, error);
        return createErrorResponse(
          `Error retrieving SAP Help content. Please try again later.`,
          timing.requestId
        );
      }
    }
  • Tool schema registration in ListToolsRequestSchema response, defining the name, description, and input schema requiring 'result_id' parameter.
                name: "sap_help_get", 
                description: `GET SAP HELP PAGE: sap_help_get(result_id="sap-help-12345abc")
    
    FUNCTION NAME: sap_help_get (or mcp_sap-docs-remote_sap_help_get)
    
    RETRIEVES: Complete SAP Help Portal page content
    REQUIRES: Exact result_id from sap_help_search
    
    USAGE PATTERN:
    1. Get ID from sap_help_search results  
    2. Use exact ID (don't modify the format)
    3. Receive full page content + metadata`,
                inputSchema: {
                  type: "object",
                  properties: {
                    result_id: {
                      type: "string",
                      description: "Exact ID from sap_help_search results. Copy the ID exactly as returned.",
                      examples: [
                        "sap-help-12345abc",
                        "sap-help-98765def"
                      ]
                    }
                  },
                  required: ["result_id"]
                }
              },
Behavior3/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It states this is a retrieval operation ('GET', 'RETRIEVES') and mentions receiving 'full page content + metadata', which provides some behavioral context. However, it doesn't describe error conditions, rate limits, authentication requirements, or what happens with invalid IDs. The description adds basic context but lacks comprehensive behavioral details.

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

Conciseness5/5

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

The description is efficiently structured with clear sections (FUNCTION NAME, RETRIEVES, REQUIRES, USAGE PATTERN) that make information easy to parse. Every sentence serves a purpose: establishing identity, specifying what's retrieved, stating prerequisites, and providing usage steps. There's no wasted verbiage or redundant information.

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

Completeness4/5

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

For a single-parameter retrieval tool with no output schema, the description provides strong contextual completeness. It explains the tool's role in the workflow, parameter requirements, and what to expect in return. The main gap is the lack of output format details (what 'full page content + metadata' actually contains), but given the tool's relative simplicity and clear positioning, the description is largely complete.

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

Parameters4/5

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

The schema description coverage is 100% with clear documentation of the single parameter. The description reinforces the schema by emphasizing 'Exact ID from sap_help_search results' and 'Use exact ID (don't modify the format)', adding practical usage guidance beyond the schema's technical specification. This provides valuable semantic context about the parameter's origin and handling requirements.

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

Purpose5/5

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

The description explicitly states the verb ('GET', 'RETRIEVES') and resource ('SAP Help Portal page content'), making the purpose crystal clear. It distinguishes from sibling tools like sap_help_search (which finds IDs) and sap_community_search (different content source). The description goes beyond just restating the name to specify what exactly is retrieved.

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

Usage Guidelines5/5

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

The description provides explicit, step-by-step guidance on when and how to use this tool: '1. Get ID from sap_help_search results 2. Use exact ID 3. Receive full page content'. It clearly positions this as the second step after using sap_help_search, creating a clear workflow relationship with its sibling tool.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

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

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marianfoo/mcp-sap-docs'

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