Skip to main content
Glama
Luminaire1337

MTA:SA Documentation MCP Server

get_function_docs

Retrieve official documentation for a specific MTA:SA function or event using its canonical name. Avoid manual web browsing for accurate, cached results.

Instructions

Fetch authoritative docs for exactly ONE MTA:SA function/event by canonical name. Preferred over manual web browsing. For multiple names, use get_multiple_function_docs in one call.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
function_nameYesFunction/event name (case-insensitive)
use_cacheNoWhether to use cached documentation
include_optional_argumentsNoWhether to include optional arguments in the parameters section

Implementation Reference

  • src/index.ts:305-396 (registration)
    Registration of the 'get_function_docs' tool with schema and handler callback on the MCP server.
    // Register tool: get_function_docs
    server.registerTool(
      "get_function_docs",
      {
        description:
          "Fetch authoritative docs for exactly ONE MTA:SA function/event by canonical name. Preferred over manual web browsing. For multiple names, use get_multiple_function_docs in one call.",
        inputSchema: {
          function_name: z
            .string()
            .describe("Function/event name (case-insensitive)"),
          use_cache: z
            .boolean()
            .optional()
            .default(true)
            .describe("Whether to use cached documentation"),
          include_optional_arguments: z
            .boolean()
            .optional()
            .default(false)
            .describe(
              "Whether to include optional arguments in the parameters section",
            ),
        },
      },
      async ({
        function_name,
        use_cache,
        include_optional_arguments,
      }): Promise<CallToolResult> => {
        const normalizedName = normalizeFunctionInput(function_name);
        if (!normalizedName) {
          return {
            content: [
              {
                type: "text",
                text: "Function name is required.",
              },
            ],
          };
        }
    
        const func = findMetadataByName(normalizedName);
    
        if (!func) {
          return {
            content: [
              {
                type: "text",
                text: `Function/event "${function_name}" not found in MTA:SA metadata. Use search_functions or search_events to find the correct name.`,
              },
            ],
          };
        }
    
        const doc = await fetchFunctionDoc(func.name, use_cache);
        if (!doc) {
          return {
            content: [
              {
                type: "text",
                text: `Failed to fetch documentation for ${func.name}. The wiki page may not exist or be unavailable.`,
              },
            ],
          };
        }
    
        const formatted = formatDocumentation(doc, func, {
          includeExamples: true,
          includeOptionalArguments: include_optional_arguments,
        });
        const suggestedRelated = findRelatedFunctions(func.name, 5)
          .filter((candidate) => candidate.name !== func.name)
          .slice(0, 5);
    
        let relatedHint = "";
        if (suggestedRelated.length > 0) {
          relatedHint =
            "\n\nSuggested follow-up entries:\n" +
            formatFunctionList(suggestedRelated) +
            "\n\nNext: call `get_multiple_function_docs` with the exact names above if you need implementation context.";
        }
    
        return {
          content: [
            {
              type: "text",
              text: `${formatted}${relatedHint}`,
            },
          ],
        };
      },
    );
  • Input schema definition for get_function_docs: function_name (string, required), use_cache (boolean, optional, default true), include_optional_arguments (boolean, optional, default false).
    server.registerTool(
      "get_function_docs",
      {
        description:
          "Fetch authoritative docs for exactly ONE MTA:SA function/event by canonical name. Preferred over manual web browsing. For multiple names, use get_multiple_function_docs in one call.",
        inputSchema: {
          function_name: z
            .string()
            .describe("Function/event name (case-insensitive)"),
          use_cache: z
            .boolean()
            .optional()
            .default(true)
            .describe("Whether to use cached documentation"),
          include_optional_arguments: z
            .boolean()
            .optional()
            .default(false)
            .describe(
              "Whether to include optional arguments in the parameters section",
            ),
        },
      },
  • Handler function for get_function_docs: normalizes function_name, looks up metadata via findMetadataByName, fetches docs via fetchFunctionDoc, formats output via formatDocumentation, and suggests related functions.
      async ({
        function_name,
        use_cache,
        include_optional_arguments,
      }): Promise<CallToolResult> => {
        const normalizedName = normalizeFunctionInput(function_name);
        if (!normalizedName) {
          return {
            content: [
              {
                type: "text",
                text: "Function name is required.",
              },
            ],
          };
        }
    
        const func = findMetadataByName(normalizedName);
    
        if (!func) {
          return {
            content: [
              {
                type: "text",
                text: `Function/event "${function_name}" not found in MTA:SA metadata. Use search_functions or search_events to find the correct name.`,
              },
            ],
          };
        }
    
        const doc = await fetchFunctionDoc(func.name, use_cache);
        if (!doc) {
          return {
            content: [
              {
                type: "text",
                text: `Failed to fetch documentation for ${func.name}. The wiki page may not exist or be unavailable.`,
              },
            ],
          };
        }
    
        const formatted = formatDocumentation(doc, func, {
          includeExamples: true,
          includeOptionalArguments: include_optional_arguments,
        });
        const suggestedRelated = findRelatedFunctions(func.name, 5)
          .filter((candidate) => candidate.name !== func.name)
          .slice(0, 5);
    
        let relatedHint = "";
        if (suggestedRelated.length > 0) {
          relatedHint =
            "\n\nSuggested follow-up entries:\n" +
            formatFunctionList(suggestedRelated) +
            "\n\nNext: call `get_multiple_function_docs` with the exact names above if you need implementation context.";
        }
    
        return {
          content: [
            {
              type: "text",
              text: `${formatted}${relatedHint}`,
            },
          ],
        };
      },
    );
  • fetchFunctionDoc: fetches wiki documentation for a function by name, with caching (SQLite-backed), HTML fetching from multiple URL variants, parsing, embedding generation, and storage.
    export const fetchFunctionDoc = async (
      functionName: string,
      useCache: boolean = true,
    ): Promise<CachedDoc | null> => {
      try {
        const canonicalName = normalizeInputName(functionName);
        if (canonicalName.length === 0) {
          throw new Error("Function name is required");
        }
    
        // Check cache
        if (useCache) {
          const cached = queries.getDoc().get(canonicalName) as
            | CachedDoc
            | undefined;
          if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
            console.error(`Using cached doc for ${canonicalName}`);
            return cached;
          }
        }
    
        // Try multiple wiki URL variants
        console.error(`Fetching ${canonicalName} from wiki...`);
        const urlVariants = getUrlVariants(canonicalName);
        let html: string | null = null;
        let usedUrl: string | null = null;
    
        for (const variant of urlVariants) {
          const url = `${WIKI_BASE_URL}/${variant}`;
          try {
            const response = await fetch(url);
            if (response.ok) {
              html = await response.text();
              // Use the final redirected URL if available
              usedUrl = response.url || url;
              break;
            }
          } catch {
            // ignore and try next
          }
        }
        if (!html || !usedUrl) {
          throw new Error(`Could not fetch wiki page for ${canonicalName}`);
        }
    
        const docData = parseDocumentation(html, canonicalName, usedUrl);
    
        // Extract related functions from wiki
        const relatedList: string[] = [];
        const seeAlsoMatch = html.match(/See [Aa]lso[\s\S]*?(?=<h[23]|$)/i);
        if (seeAlsoMatch) {
          const links = seeAlsoMatch[0].matchAll(/title="([^"]+)"/g);
          for (const link of links) {
            const relatedName = link[1];
            if (!relatedName) {
              continue;
            }
    
            const resolvedName = resolveFunctionName(relatedName);
            if (resolvedName) {
              relatedList.push(resolvedName);
            }
          }
        }
    
        // Generate embedding from full text
        const embedding = generateTextEmbedding(docData.full_text);
        const embeddingBuffer = vectorToBuffer(embedding);
    
        const relatedFromParser = docData.related_functions
          .split(",")
          .map((name) => resolveFunctionName(normalizeInputName(name)))
          .filter((name): name is string => typeof name === "string");
    
        const doc: CachedDoc = {
          ...docData,
          function_name: canonicalName,
          related_functions: dedupe([...relatedFromParser, ...relatedList]).join(
            ", ",
          ),
        };
    
        // Store in database
        queries
          .insertDoc()
          .run(
            doc.function_name,
            doc.url,
            doc.description,
            doc.syntax,
            doc.examples,
            doc.parameters,
            doc.returns,
            doc.related_functions,
            doc.full_text,
            doc.timestamp,
            embeddingBuffer,
            doc.deprecated || null,
          );
    
        return doc;
      } catch (error) {
        console.error(`Failed to fetch ${functionName}:`, error);
        return null;
      }
    };
  • formatDocumentation: formats a CachedDoc + MtasaFunction into a Markdown string with description, syntax, parameters (optionally filtered for optional args), returns, examples, and related functions.
    export const formatDocumentation = (
      doc: CachedDoc,
      funcInfo: MtasaFunction,
      optionsOrIncludeExamples?: boolean | FormatDocumentationOptions,
    ): string => {
      const { includeExamples, includeOptionalArguments } = normalizeOptions(
        optionsOrIncludeExamples,
      );
    
      let output = `# ${funcInfo.name}\n\n`;
      output += `**Category:** ${funcInfo.category}\n`;
      output += `**Side:** ${funcInfo.side}\n`;
      output += `**URL:** ${doc.url}\n\n`;
    
      if (doc.deprecated) {
        output += `⚠️ **DEPRECATED:** ${doc.deprecated}\n\n`;
      }
    
      if (doc.description) {
        output += `## Description\n${doc.description}\n\n`;
      }
    
      if (doc.syntax) {
        output += `## Syntax\n`;
        const syntaxParts = doc.syntax.split("\n---\n");
        syntaxParts.forEach((syntax) => {
          output += `\`\`\`lua\n${syntax}\n\`\`\`\n\n`;
        });
      }
    
      const parameters = includeOptionalArguments
        ? doc.parameters
        : filterOptionalArguments(doc.parameters);
    
      if (parameters) {
        output += `## Parameters\n${parameters}\n\n`;
      }
    
      if (doc.returns) {
        output += `## Returns\n${doc.returns}\n\n`;
      }
    
      if (includeExamples && doc.examples) {
        output += `## Examples\n\n`;
        const exampleParts = doc.examples.split("\n---\n");
        exampleParts.forEach((example, i) => {
          output += `### Example ${i + 1}\n\`\`\`lua\n${example}\n\`\`\`\n\n`;
        });
      }
    
      if (doc.related_functions) {
        output += `## Related Functions\n${doc.related_functions}\n\n`;
      }
    
      return output;
    };
Behavior3/5

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

No annotations are provided, so the description must carry the burden. It implies a read-only operation ('Fetch authoritative docs') but does not explicitly state whether it modifies state, requires authentication, or has rate limits. It lacks details about error handling or behavior for invalid names, but the safety profile is generally inferable.

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?

Three sentences with no fluff. All sentences add value: purpose, preference, and sibling guidance. Front-loaded with the core action.

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?

Lacks details about output format, error handling, caching behavior (despite a cache parameter), and prerequisites. For a simple lookup tool, the missing information is moderate. No output schema to compensate.

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

Parameters3/5

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

Schema coverage is 100% with all three parameters having descriptions. The description does not add extra meaning beyond what the schema already provides for each parameter, so baseline 3 is appropriate.

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 it fetches docs for exactly one MTA:SA function/event by canonical name, and distinguishes from the sibling 'get_multiple_function_docs' by specifying the single-name scope. It also positions itself as preferred over manual browsing.

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?

Explicitly says to use this for single names and to use get_multiple_function_docs for multiple names. Also advises it's preferred over manual web browsing, providing clear when-to-use guidance.

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/Luminaire1337/mtasa-docs-mcp'

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