Skip to main content
Glama
marianfoo

SAP Documentation MCP Server

fetch

Retrieve full SAP documentation content and metadata by providing a specific document ID from search results, returning structured JSON for developer reference.

Instructions

GET SPECIFIC DOCS: fetch(id="result_id")

FUNCTION NAME: fetch

RETRIEVES: Full content from search results WORKS WITH: Document IDs returned by search

ChatGPT COMPATIBLE: • Uses "id" parameter (required by ChatGPT) • Returns structured JSON content • Includes full document text and metadata

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idYesUnique document ID from search results. Use exact IDs returned by search.

Implementation Reference

  • MCP tool handler for 'fetch': extracts id parameter, calls fetchLibraryDocumentation, formats structured JSON response with document content.
    if (name === "sap_docs_get" || name === "fetch") {
      // Handle both old format (library_id) and new ChatGPT format (id)
      const library_id = (args as any).library_id || (args as any).id;
      const topic = (args as any).topic || "";
      
      if (!library_id) {
        const timing = logger.logToolStart(name, 'missing_id', clientMetadata);
        logger.logToolError(name, timing.requestId, timing.startTime, new Error('Missing id parameter'));
        return createErrorResponse(
          `Missing required parameter: id. Please provide a document ID from search results.`,
          timing.requestId
        );
      }
      
      // Enhanced logging with timing
      const searchKey = library_id + (topic ? `/${topic}` : '');
      const timing = logger.logToolStart(name, searchKey, clientMetadata);
      
      try {
        const text = await fetchLibraryDocumentation(library_id, topic);
        
        if (!text) {
          logger.logToolSuccess(name, timing.requestId, timing.startTime, 0);
          return createErrorResponse(
            `Nothing found for ${library_id}`,
            timing.requestId
          );
        }
        
        // Transform document content to ChatGPT-compatible format
        const config = getDocUrlConfig(library_id);
        const docUrl = config ? generateDocumentationUrl(library_id, '', text, config) : null;
        const document: DocumentResult = {
          id: library_id,
          title: library_id.replace(/^\//, '').replace(/\//g, ' > ') + (topic ? ` (${topic})` : ''),
          text: text,
          url: docUrl || `#${library_id}`,
          metadata: {
            source: 'sap-docs',
            library: library_id,
            topic: topic || undefined,
            contentLength: text.length
          }
        };
        
        logger.logToolSuccess(name, timing.requestId, timing.startTime, 1, { 
          contentLength: text.length,
          libraryId: library_id,
          topic: topic || undefined
        });
        
        return createDocumentResponse(document);
      } catch (error) {
        logger.logToolError(name, timing.requestId, timing.startTime, error);
        return createErrorResponse(
          `Error retrieving documentation for ${library_id}. Please try again later.`,
          timing.requestId
        );
      }
    }
  • Tool schema definition: name 'fetch', description, inputSchema requiring 'id' string parameter with examples.
                name: "fetch",
                description: `GET SPECIFIC DOCS: fetch(id="result_id")
    
    FUNCTION NAME: fetch
    
    RETRIEVES: Full content from search results
    WORKS WITH: Document IDs returned by search
    
    ChatGPT COMPATIBLE:
    • Uses "id" parameter (required by ChatGPT)
    • Returns structured JSON content
    • Includes full document text and metadata`,
                inputSchema: {
                  type: "object",
                  properties: {
                    id: {
                      type: "string",
                      description: "Unique document ID from search results. Use exact IDs returned by search.",
                      examples: [
                        "/cap/guides/domain-modeling",
                        "/sapui5/controls/button-properties", 
                        "/openui5-api/sap/m/Button",
                        "/abap-docs-758/inline-declarations",
                        "community-12345"
                      ]
                    }
                  },
                  required: ["id"]
                }
              },
  • Registers 'fetch' tool in ListToolsRequestSchema handler by including it in the tools array.
        srv.setRequestHandler(ListToolsRequestSchema, async () => {
          return {
            tools: [
              {
                name: "sap_community_search", 
                description: `SEARCH SAP COMMUNITY: sap_community_search(query="search terms")
    
    FUNCTION NAME: sap_community_search (or mcp_sap-docs-remote_sap_community_search)
    
    FINDS: Blog posts, discussions, solutions from SAP Community
    INCLUDES: Engagement data (kudos), ranked by "Best Match"
    
    TYPICAL WORKFLOW:
    1. sap_community_search(query="your problem + error code")
    2. fetch(id="community-12345") for full posts
    
    BEST FOR TROUBLESHOOTING:
    • Include error codes: "415 error", "500 error"
    • Be specific: "CAP action binary upload 415"
    • Use real scenarios: "wizard implementation issues"`,
                inputSchema: {
                  type: "object",
                  properties: {
                    query: {
                      type: "string",
                      description: "Search terms for SAP Community. Include error codes and specific technical details.",
                      examples: [
                        "CAP action parameter binary file upload 415 error",
                        "wizard implementation best practices",
                        "fiori elements authentication",
                        "UI5 deployment issues",
                        "wdi5 test automation problems"
                      ]
                    }
                  },
                  required: ["query"]
                }
              },
              {
                name: "sap_help_search",
                description: `SEARCH SAP HELP PORTAL: sap_help_search(query="product + topic")
    
    FUNCTION NAME: sap_help_search (or mcp_sap-docs-remote_sap_help_search)
    
    SEARCHES: Official SAP Help Portal (help.sap.com)
    COVERS: Product guides, implementation guides, technical documentation
    
    TYPICAL WORKFLOW:
    1. sap_help_search(query="product name + configuration topic")
    2. sap_help_get(result_id="sap-help-12345abc")
    
    BEST PRACTICES:
    • Include product names: "S/4HANA", "BTP", "Fiori"
    • Add specific tasks: "configuration", "setup", "deployment"
    • Use official SAP terminology`,
                inputSchema: {
                  type: "object",
                  properties: {
                    query: {
                      type: "string",
                      description: "Search terms for SAP Help Portal. Include product names and specific topics.",
                      examples: [
                        "S/4HANA configuration",
                        "Fiori Launchpad setup", 
                        "BTP integration",
                        "ABAP development guide",
                        "SAP Analytics Cloud setup"
                      ]
                    }
                  },
                  required: ["query"]
                }
              },
              {
                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"]
                }
              },
              {
                name: "search",
                description: `SEARCH SAP DOCS: search(query="search terms")
    
    FUNCTION NAME: search
    
    COVERS: ABAP (all versions), UI5, CAP, wdi5, OpenUI5 APIs, Cloud SDK
    AUTO-DETECTS: ABAP versions from query (e.g. "LOOP 7.57", defaults to 7.58)
    
    TYPICAL WORKFLOW:
    1. search(query="your search terms") 
    2. fetch(id="result_id_from_step_1")
    
    QUERY TIPS:
    • Be specific: "CAP action binary parameter" not just "CAP"
    • Include error codes: "415 error CAP action"
    • Use technical terms: "LargeBinary MediaType XMLHttpRequest"
    • For ABAP: Include version like "7.58" or "latest"`,
                inputSchema: {
                  type: "object",
                  properties: {
                    query: {
                      type: "string",
                      description: "Search terms using natural language. Be specific and include technical terms.",
                      examples: [
                        "CAP binary data LargeBinary MediaType",
                        "UI5 button properties",
                        "wdi5 testing locators", 
                        "ABAP SELECT statements 7.58",
                        "415 error CAP action parameter"
                      ]
                    }
                  },
                  required: ["query"]
                }
              },
              {
                name: "fetch",
                description: `GET SPECIFIC DOCS: fetch(id="result_id")
    
    FUNCTION NAME: fetch
    
    RETRIEVES: Full content from search results
    WORKS WITH: Document IDs returned by search
    
    ChatGPT COMPATIBLE:
    • Uses "id" parameter (required by ChatGPT)
    • Returns structured JSON content
    • Includes full document text and metadata`,
                inputSchema: {
                  type: "object",
                  properties: {
                    id: {
                      type: "string",
                      description: "Unique document ID from search results. Use exact IDs returned by search.",
                      examples: [
                        "/cap/guides/domain-modeling",
                        "/sapui5/controls/button-properties", 
                        "/openui5-api/sap/m/Button",
                        "/abap-docs-758/inline-declarations",
                        "community-12345"
                      ]
                    }
                  },
                  required: ["id"]
                }
              },
    
            ]
          };
        });
  • Core fetch implementation: loads doc index, resolves library/doc ID, reads source file, formats content specially for API docs/samples, handles community posts, returns markdown text.
    export async function fetchLibraryDocumentation(
      libraryIdOrDocId: string,
      topic = ""
    ): Promise<string | null> {
      // Check if this is a community post ID
      if (libraryIdOrDocId.startsWith('community-')) {
        return await getCommunityPost(libraryIdOrDocId);
      }
    
      const index = await loadIndex();
      
      // Check if this is a specific document ID
      const allDocs: Array<{lib: any, doc: any}> = [];
      for (const lib of Object.values(index)) {
        for (const doc of lib.docs) {
          allDocs.push({ lib, doc });
          // Try exact match first (for section documents with fragments)
          if (doc.id === libraryIdOrDocId) {
            const sourcePath = getSourcePath(lib.id);
            if (!sourcePath) {
              throw new Error(`Unknown library ID: ${lib.id}`);
            }
            
            const abs = path.join(PROJECT_ROOT, "sources", sourcePath, doc.relFile);
            const content = await fs.readFile(abs, "utf8");
            
            // For JavaScript API files, format the content for better readability
            if (doc.relFile && doc.relFile.endsWith('.js') && lib.id === '/openui5-api') {
              return formatJSDocContent(content, doc.title || '');
            }
            // For sample files, format them appropriately
            else if (lib.id === '/openui5-samples') {
              return formatSampleContent(content, doc.relFile, doc.title || '');
            }
            // For documented libraries, add URL context
            else if (getDocUrlConfig(lib.id)) {
              const documentationUrl = generateDocumentationUrl(lib.id, doc.relFile, content);
              const libName = lib.id.replace('/', '').toUpperCase();
              
              return `**Source:** ${libName} Documentation
    **URL:** ${documentationUrl || 'Documentation URL not available'}
    **File:** ${doc.relFile}
    
    ---
    
    ${content}
    
    ---
    
    *This content is from the ${libName} documentation. Visit the URL above for the latest version and interactive examples.*`;
            } else {
              return content;
            }
          }
        }
      }
      
      // If no exact match found and the ID contains a fragment, try stripping the fragment
      // This handles cases where fragments are used for navigation but don't exist as separate documents
      if (libraryIdOrDocId.includes('#')) {
        const baseId = libraryIdOrDocId.split('#')[0];
        
        // Try to find a document with the base ID (without fragment)
        for (const lib of Object.values(index)) {
          for (const doc of lib.docs) {
            if (doc.id === baseId) {
              const sourcePath = getSourcePath(lib.id);
              if (!sourcePath) {
                throw new Error(`Unknown library ID: ${lib.id}`);
              }
              
              const abs = path.join(PROJECT_ROOT, "sources", sourcePath, doc.relFile);
              const content = await fs.readFile(abs, "utf8");
              
              // For JavaScript API files, format the content for better readability
              if (doc.relFile && doc.relFile.endsWith('.js') && lib.id === '/openui5-api') {
                return formatJSDocContent(content, doc.title || '');
              }
              // For sample files, format them appropriately
              else if (lib.id === '/openui5-samples') {
                return formatSampleContent(content, doc.relFile, doc.title || '');
              }
              // For documented libraries, add URL context
              else if (getDocUrlConfig(lib.id)) {
                const documentationUrl = generateDocumentationUrl(lib.id, doc.relFile, content);
                const libName = lib.id.replace('/', '').toUpperCase();
                
                return `**Source:** ${libName} Documentation
    **URL:** ${documentationUrl || 'Documentation URL not available'}
    **File:** ${doc.relFile}
    
    ---
    
    ${content}
    
    ---
    
    *This content is from the ${libName} documentation. Visit the URL above for the latest version and interactive examples.*`;
              } else {
                return content;
              }
            }
          }
        }
        
        // Try library-level lookup with base ID
        const baseLib = index[baseId];
        if (baseLib) {
          const term = topic.toLowerCase();
          const targets = term
            ? baseLib.docs.filter(
                (d) =>
                  d.title.toLowerCase().includes(term) ||
                  d.description.toLowerCase().includes(term)
              )
            : baseLib.docs;
    
          if (!targets.length) return `No topic "${topic}" found inside ${baseId}.`;
    
          const parts: string[] = [];
          for (const doc of targets) {
            const sourcePath = getSourcePath(baseLib.id);
            if (!sourcePath) {
              throw new Error(`Unknown library ID: ${baseLib.id}`);
            }
            
            const abs = path.join(PROJECT_ROOT, "sources", sourcePath, doc.relFile);
            const content = await fs.readFile(abs, "utf8");
            
            // For JavaScript API files, format the content for better readability
            if (doc.relFile && doc.relFile.endsWith('.js') && baseLib.id === '/openui5-api') {
              const formattedContent = formatJSDocContent(content, doc.title || '');
              parts.push(formattedContent);
            }
            // For sample files, format them appropriately
            else if (baseLib.id === '/openui5-samples') {
              const formattedContent = formatSampleContent(content, doc.relFile, doc.title || '');
              parts.push(formattedContent);
            }
            // For documented libraries, add URL context
            else if (getDocUrlConfig(baseLib.id)) {
              const documentationUrl = generateDocumentationUrl(baseLib.id, doc.relFile, content);
              const libName = baseLib.id.replace('/', '').toUpperCase();
              
              const formattedContent = `**Source:** ${libName} Documentation
    **URL:** ${documentationUrl || 'Documentation URL not available'}
    **File:** ${doc.relFile}
    
    ---
    
    ${content}
    
    ---
    
    *This content is from the ${libName} documentation. Visit the URL above for the latest version and interactive examples.*`;
              parts.push(formattedContent);
            } else {
              parts.push(content);
            }
          }
          return parts.join("\n\n---\n\n");
        }
      }
      
      // If not a specific document ID, treat as library ID with optional topic
      const lib = index[libraryIdOrDocId];
      if (!lib) return null;
    
      // If topic is provided, first try to construct the full document ID
      if (topic) {
        const fullDocId = `${libraryIdOrDocId}/${topic}`;
        
        // Try to find exact document match first
        for (const doc of lib.docs) {
          if (doc.id === fullDocId) {
            const sourcePath = getSourcePath(lib.id);
            if (!sourcePath) {
              throw new Error(`Unknown library ID: ${lib.id}`);
            }
            
            const abs = path.join(PROJECT_ROOT, "sources", sourcePath, doc.relFile);
            const content = await fs.readFile(abs, "utf8");
            
            // Format the content appropriately based on library type
            if (doc.relFile && doc.relFile.endsWith('.js') && lib.id === '/openui5-api') {
              return formatJSDocContent(content, doc.title || '');
            } else if (lib.id === '/openui5-samples') {
              return formatSampleContent(content, doc.relFile, doc.title || '');
            } else if (getDocUrlConfig(lib.id)) {
              const documentationUrl = generateDocumentationUrl(lib.id, doc.relFile, content);
              const libName = lib.id.replace('/', '').toUpperCase();
              
              return `**Source:** ${libName} Documentation
    **URL:** ${documentationUrl || 'Documentation URL not available'}
    **File:** ${doc.relFile}
    
    ---
    
    ${content}
    
    ---
    
    *This content is from the ${libName} documentation. Visit the URL above for the latest version and interactive examples.*`;
            } else {
              return content;
            }
          }
        }
        
        // If exact match not found, fall back to topic keyword search
        const term = topic.toLowerCase();
        const targets = lib.docs.filter(
          (d) =>
            d.title.toLowerCase().includes(term) ||
            d.description.toLowerCase().includes(term)
        );
        
        if (targets.length > 0) {
          // Process the filtered documents
          const parts: string[] = [];
          for (const doc of targets) {
            const sourcePath = getSourcePath(lib.id);
            if (!sourcePath) {
              throw new Error(`Unknown library ID: ${lib.id}`);
            }
            
            const abs = path.join(PROJECT_ROOT, "sources", sourcePath, doc.relFile);
            const content = await fs.readFile(abs, "utf8");
            
            if (doc.relFile && doc.relFile.endsWith('.js') && lib.id === '/openui5-api') {
              const formattedContent = formatJSDocContent(content, doc.title || '');
              parts.push(formattedContent);
            } else if (lib.id === '/openui5-samples') {
              const formattedContent = formatSampleContent(content, doc.relFile, doc.title || '');
              parts.push(formattedContent);
            } else if (getDocUrlConfig(lib.id)) {
              const documentationUrl = generateDocumentationUrl(lib.id, doc.relFile, content);
              const libName = lib.id.replace('/', '').toUpperCase();
              
              const formattedContent = `**Source:** ${libName} Documentation
    **URL:** ${documentationUrl || 'Documentation URL not available'}
    **File:** ${doc.relFile}
    
    ---
    
    ${content}
    
    ---
    
    *This content is from the ${libName} documentation. Visit the URL above for the latest version and interactive examples.*`;
              parts.push(formattedContent);
            } else {
              parts.push(content);
            }
          }
          return parts.join("\n\n---\n\n");
        }
        
        return `No topic "${topic}" found inside ${libraryIdOrDocId}.`;
      }
      
      // No topic provided, return all library documents
      const targets = lib.docs;
      if (!targets.length) return `No documents found inside ${libraryIdOrDocId}.`;
    
      const parts: string[] = [];
      for (const doc of targets) {
        const sourcePath = getSourcePath(lib.id);
        if (!sourcePath) {
          throw new Error(`Unknown library ID: ${lib.id}`);
        }
        
        const abs = path.join(PROJECT_ROOT, "sources", sourcePath, doc.relFile);
        const content = await fs.readFile(abs, "utf8");
        
        // For JavaScript API files, format the content for better readability
        if (doc.relFile && doc.relFile.endsWith('.js') && lib.id === '/openui5-api') {
          const formattedContent = formatJSDocContent(content, doc.title || '');
          parts.push(formattedContent);
        }
        // For sample files, format them appropriately
        else if (lib.id === '/openui5-samples') {
          const formattedContent = formatSampleContent(content, doc.relFile, doc.title || '');
          parts.push(formattedContent);
        }
        // For documented libraries, add URL context
        else if (getDocUrlConfig(lib.id)) {
          const documentationUrl = generateDocumentationUrl(lib.id, doc.relFile, content);
          const libName = lib.id.replace('/', '').toUpperCase();
          
          const formattedContent = `**Source:** ${libName} Documentation
    **URL:** ${documentationUrl || 'Documentation URL not available'}
    **File:** ${doc.relFile}
    
    ---
    
    ${content}
    
    ---
    
    *This content is from the ${libName} documentation. Visit the URL above for the latest version and interactive examples.*`;
          parts.push(formattedContent);
        } else {
          parts.push(content);
        }
      }
      return parts.join("\n\n---\n\n");
    }
  • Helper to format OpenUI5 API JavaScript files: extracts JSDoc, metadata, properties/events/aggregations into structured markdown.
    // Format JavaScript content for better readability in documentation context
    function formatJSDocContent(content: string, controlName: string): string {
      const lines = content.split('\n');
      const result: string[] = [];
      
      result.push(`# ${controlName} - OpenUI5 Control API`);
      result.push('');
      
      // Extract main JSDoc comment
      const mainJSDocMatch = content.match(/\/\*\*\s*([\s\S]*?)\*\//);
      if (mainJSDocMatch) {
        const cleanDoc = mainJSDocMatch[1]
          .split('\n')
          .map(line => line.replace(/^\s*\*\s?/, ''))
          .join('\n')
          .trim();
        
        result.push('## Description');
        result.push('');
        result.push(cleanDoc);
        result.push('');
      }
      
      // Extract metadata section
      const metadataMatch = content.match(/metadata\s*:\s*\{([\s\S]*?)\n\s*\}/);
      if (metadataMatch) {
        result.push('## Control Metadata');
        result.push('');
        result.push('```javascript');
        result.push('metadata: {');
        result.push(metadataMatch[1]);
        result.push('}');
        result.push('```');
        result.push('');
      }
      
      // Extract properties
      const propertiesMatch = content.match(/properties\s*:\s*\{([\s\S]*?)\n\s*\}/);
      if (propertiesMatch) {
        result.push('## Properties');
        result.push('');
        result.push('```javascript');
        result.push(propertiesMatch[1]);
        result.push('```');
        result.push('');
      }
      
      // Extract events
      const eventsMatch = content.match(/events\s*:\s*\{([\s\S]*?)\n\s*\}/);
      if (eventsMatch) {
        result.push('## Events');
        result.push('');
        result.push('```javascript');
        result.push(eventsMatch[1]);
        result.push('```');
        result.push('');
      }
      
      // Extract aggregations
      const aggregationsMatch = content.match(/aggregations\s*:\s*\{([\s\S]*?)\n\s*\}/);
      if (aggregationsMatch) {
        result.push('## Aggregations');
        result.push('');
        result.push('```javascript');
        result.push(aggregationsMatch[1]);
        result.push('```');
        result.push('');
      }
      
      // Extract associations
      const associationsMatch = content.match(/associations\s*:\s*\{([\s\S]*?)\n\s*\}/);
      if (associationsMatch) {
        result.push('## Associations');
        result.push('');
        result.push('```javascript');
        result.push(associationsMatch[1]);
        result.push('```');
        result.push('');
      }
      
      result.push('---');
      result.push('');
      result.push('### Full Source Code');
      result.push('');
      result.push('```javascript');
      result.push(content);
      result.push('```');
      
      return result.join('\n');
    }
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 adds useful context about ChatGPT compatibility, structured JSON returns, and inclusion of full text and metadata. However, it doesn't cover important behavioral aspects like error handling, rate limits, authentication needs, or whether this is a read-only operation (though 'GET' implies it).

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

Conciseness3/5

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

The description is appropriately sized but has structural issues. It uses all-caps headers inconsistently and includes redundant information (repeating 'FUNCTION NAME: fetch' when the tool name is already 'fetch'). The content is front-loaded with the core purpose, but the formatting could be cleaner and more streamlined.

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

Completeness3/5

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

Given the tool's moderate complexity (single parameter, no output schema, no annotations), the description is reasonably complete for basic usage. It explains what the tool does, what it returns, and how to use the parameter. However, it lacks information about error cases, response format details, or performance characteristics that would be helpful for an agent.

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 only one parameter well-documented in the schema. The description adds value by emphasizing the parameter is 'required by ChatGPT' and clarifying it works with 'exact IDs returned by search', providing practical usage context beyond the schema's technical specification.

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

Purpose5/5

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

The description clearly states the tool's purpose with specific verbs ('GET', 'RETRIEVES') and resources ('SPECIFIC DOCS', 'Full content from search results'). It distinguishes from sibling tools by focusing on fetching specific documents rather than searching, with explicit mention of working with 'Document IDs returned by search'.

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool ('Works with: Document IDs returned by search'), indicating it should be used after a search operation. However, it doesn't explicitly state when NOT to use it or name specific alternatives among the sibling tools, though the context implies it complements search tools.

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