Skip to main content
Glama
appian-design

Design System MCP Server

get-sail-guidance

Retrieve SAIL coding guidance and best practices from Appian's Aurora design system documentation. Specify technology like HTML or CSS for broader support.

Instructions

Get SAIL coding guidance and best practices

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
technologyNoTechnology or framework (e.g., 'sail', 'html', 'css')

Implementation Reference

  • src/index.ts:474-549 (registration)
    Registration of the get-sail-guidance tool with schema and handler on the MCP server
    // Tool 7: Get SAIL guidance
    server.tool(
      "get-sail-guidance",
      "Get SAIL coding guidance and best practices",
      {
        technology: z.string().describe("Technology or framework (e.g., 'sail', 'html', 'css')").optional(),
      },
      async ({ technology }) => {
        // If no technology specified, list available guides
        if (!technology) {
          const codingGuides = designSystemData['coding-guides'];
          const guides = Object.entries(codingGuides).map(
            ([key, guide]) => `${key}: ${guide.title} - ${guide.body}`
          );
          
          return {
            content: [
              {
                type: "text",
                text: `Available coding guides:\n\n${guides.join("\n\n")}\n\nUse get-component-details with category 'coding-guides' to access specific guides.`,
              },
            ],
          };
        }
        
        // Look for technology-specific guide
        const normalizedTech = technology.toLowerCase();
        const codingGuides = designSystemData['coding-guides'];
        
        // Check if there's a direct match or partial match
        let matchedGuide = null;
        let matchedKey = null;
        
        for (const [key, guide] of Object.entries(codingGuides)) {
          if (key.includes(normalizedTech) || guide.title.toLowerCase().includes(normalizedTech)) {
            matchedGuide = guide;
            matchedKey = key;
            break;
          }
        }
        
        if (!matchedGuide) {
          return {
            content: [
              {
                type: "text",
                text: `No coding guide found for "${technology}". Available guides: ${Object.keys(codingGuides).join(", ")}`,
              },
            ],
          };
        }
        
        // Fetch the full guide content
        const repoContent = await fetchRepoContent(matchedGuide.filePath);
        
        if (!repoContent) {
          return {
            content: [
              {
                type: "text",
                text: `Failed to fetch ${matchedGuide.title} guide. Basic info: ${matchedGuide.body}`,
              },
            ],
          };
        }
        
        return {
          content: [
            {
              type: "text",
              text: `# ${matchedGuide.title}\n\n${repoContent.content}`,
            },
          ],
        };
      },
    );
  • Handler function for get-sail-guidance: lists all available coding guides when no technology is specified, looks up matching guide by technology name, fetches full content via fetchRepoContent, and returns the guide text
    async ({ technology }) => {
      // If no technology specified, list available guides
      if (!technology) {
        const codingGuides = designSystemData['coding-guides'];
        const guides = Object.entries(codingGuides).map(
          ([key, guide]) => `${key}: ${guide.title} - ${guide.body}`
        );
        
        return {
          content: [
            {
              type: "text",
              text: `Available coding guides:\n\n${guides.join("\n\n")}\n\nUse get-component-details with category 'coding-guides' to access specific guides.`,
            },
          ],
        };
      }
      
      // Look for technology-specific guide
      const normalizedTech = technology.toLowerCase();
      const codingGuides = designSystemData['coding-guides'];
      
      // Check if there's a direct match or partial match
      let matchedGuide = null;
      let matchedKey = null;
      
      for (const [key, guide] of Object.entries(codingGuides)) {
        if (key.includes(normalizedTech) || guide.title.toLowerCase().includes(normalizedTech)) {
          matchedGuide = guide;
          matchedKey = key;
          break;
        }
      }
      
      if (!matchedGuide) {
        return {
          content: [
            {
              type: "text",
              text: `No coding guide found for "${technology}". Available guides: ${Object.keys(codingGuides).join(", ")}`,
            },
          ],
        };
      }
      
      // Fetch the full guide content
      const repoContent = await fetchRepoContent(matchedGuide.filePath);
      
      if (!repoContent) {
        return {
          content: [
            {
              type: "text",
              text: `Failed to fetch ${matchedGuide.title} guide. Basic info: ${matchedGuide.body}`,
            },
          ],
        };
      }
      
      return {
        content: [
          {
            type: "text",
            text: `# ${matchedGuide.title}\n\n${repoContent.content}`,
          },
        ],
      };
    },
  • Helper function that fetches markdown content from GitHub repository, decodes base64, and parses frontmatter into structured sections
    async function fetchRepoContent(filePath: string): Promise<ParsedMarkdown | null> {
      try {
        const url = `https://api.github.com/repos/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/contents/${filePath}`;
        console.error(`[DEBUG] Fetching: ${filePath}`);
        
        const response = await fetch(url, {
          headers: {
            'Authorization': `token ${GITHUB_CONFIG.token}`,
            'Accept': 'application/vnd.github.v3+json',
            'User-Agent': 'design-system-mcp-server'
          }
        });
        
        if (!response.ok) {
          console.error(`[ERROR] GitHub API error for ${filePath}: ${response.status} ${response.statusText}`);
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        
        // GitHub API returns base64 encoded content
        const content = atob(data.content);
        console.error(`[DEBUG] Content fetched successfully: ${content.length} characters`);
        
        const parsed = parseFrontmatter(content);
        console.error(`[DEBUG] Content parsed: Design=${parsed.designSection.length}chars, Development=${parsed.developmentSection.length}chars`);
        
        return parsed;
      } catch (error) {
        console.error(`[ERROR] Failed to fetch repo content for ${filePath}:`, error);
        return null;
      }
    }
  • Input schema for get-sail-guidance: optional technology string parameter
    {
      technology: z.string().describe("Technology or framework (e.g., 'sail', 'html', 'css')").optional(),
  • Definition of the 'sail-coding-guide' data item in the designSystemData registry that maps to the guide content fetched by the tool
    'coding-guides': {
      'sail-coding-guide': {
        title: 'SAIL Coding Guide',
        body: 'Comprehensive guide for generating valid Appian SAIL interfaces using documented components and best practices.',
        filePath: 'docs/SAIL_CODING_GUIDE.md'
      }
    }
Behavior3/5

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

With no annotations, the description bears the full burden of behavioral disclosure. It implies a read-only operation by stating 'Get', but it does not detail any behaviors like authentication needs, rate limits, or side effects. For a simple read, the minimal description is acceptable but could be improved.

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

Conciseness4/5

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

The description is a single, concise sentence that conveys the core purpose. It is front-loaded and contains no extraneous words. However, it could be slightly expanded to include more context without losing conciseness.

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 single parameter and lack of output schema, the description minimally covers what the tool does. It does not mention what form the guidance takes (e.g., list, text block) or any filtering behavior. It is adequate but leaves the agent without full context of the response.

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 description coverage is 100%, so the baseline is 3. The description does not add further meaning to the 'technology' parameter beyond what is already in the schema. It provides no examples, defaults, or formatting hints.

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

Purpose4/5

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

The description clearly states the tool's function: 'Get SAIL coding guidance and best practices'. It specifies a verb ('Get') and a resource ('SAIL coding guidance'), which differentiates it from sibling tools focused on components, content sources, and categories. However, it could be more specific about the scope (e.g., for a given technology).

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It does not mention exclusions, prerequisites, or sibling tools. The agent receives no context about situations where this tool is preferred over others.

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/appian-design/aurora-mcp'

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