Skip to main content
Glama
tanmay4l

Futarchy MCP Server

by tanmay4l

getProposalSentiment

Analyze sentiment for DAO proposals using Discord and Twitter data to gauge community reactions and inform decision-making.

Instructions

Get sentiment analysis for a specific proposal based on Discord and Twitter data

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
proposalIdYesThe ID of the proposal to analyze

Implementation Reference

  • The MCP tool handler function that executes the tool logic: calls the API client to get sentiment analysis, handles success/error responses, and formats the output as MCP-standard content blocks.
    async ({ proposalId }) => {
      try {
        const response = await apiClient.getProposalSentimentAnalysis(proposalId);
        
        if (!response.success) {
          return {
            content: [
              {
                type: "text" as const,
                text: response.error || 'Unknown error',
              },
            ],
            isError: true,
          };
        }
        
        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(response.data, null, 2),
            },
          ],
        };
      } catch (error: any) {
        return {
          content: [
            {
              type: "text" as const,
              text: `Error fetching sentiment analysis for proposal: ${error.message || 'Unknown error'}`,
            },
          ],
          isError: true,
        };
      }
    }
  • Zod schema for input validation of the tool parameters (proposalId: string).
    {
      proposalId: z.string().describe("The ID of the proposal to analyze"),
    },
  • Registration of the 'getProposalSentiment' tool with the MCP server using server.tool().
    server.tool(
      "getProposalSentiment",
      "Get sentiment analysis for a specific proposal based on Discord and Twitter data",
      {
        proposalId: z.string().describe("The ID of the proposal to analyze"),
      },
      async ({ proposalId }) => {
        try {
          const response = await apiClient.getProposalSentimentAnalysis(proposalId);
          
          if (!response.success) {
            return {
              content: [
                {
                  type: "text" as const,
                  text: response.error || 'Unknown error',
                },
              ],
              isError: true,
            };
          }
          
          return {
            content: [
              {
                type: "text" as const,
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: "text" as const,
                text: `Error fetching sentiment analysis for proposal: ${error.message || 'Unknown error'}`,
              },
            ],
            isError: true,
          };
        }
      }
    );
  • Core helper function implementing the sentiment analysis logic: fetches messages from Discord and Twitter (with fallback data), analyzes sentiment using the 'sentiment' library, categorizes concerns, and returns structured SentimentAnalysis data.
    export async function getProposalSentimentAnalysis(proposalId: string): Promise<SentimentAnalysis> {
      try {
        // Fetch data from Discord and Twitter
        const discordMessages = await fetchDiscordMessages(proposalId);
        const twitterTweets = await fetchTwitterTweets(proposalId);
        
        // Combine all text for analysis
        const allTexts = [...discordMessages, ...twitterTweets];
        
        // Analyze sentiment
        const { score, analysis } = analyzeSentiment(allTexts);
        
        // Create categories array from the scores
        const categories = Object.entries(analysis.categoryScores).map(([name, score]) => ({
          name,
          score: score as number
        }));
        
        // Sort categories by score (descending)
        categories.sort((a, b) => b.score - a.score);
        
        // Format the response
        const sentimentAnalysis: SentimentAnalysis = {
          proposalId,
          sentimentScore: score,
          primaryCategory: categories[0].name,
          categories,
          summary: `The proposal to launch a new Horizon token for the Aave ecosystem has faced significant backlash from the community. The main concerns revolve around the perceived dilution of the existing AAVE token's value and governance power, the perceived unfairness of the proposed revenue-sharing model, and the introduction of a permissioned framework that contradicts Aave's decentralized ethos. Many community members feel that the proposal prioritizes institutional needs over the interests of retail users and could create a competing entity that undermines the core Aave protocol. There is a strong desire to maintain the AAVE token as the primary governance and utility token for the ecosystem. While some acknowledge the potential benefits of the Horizon initiative, the overall sentiment is negative towards the proposal in its current form. Suggestions include exploring ways to leverage the existing AAVE token and infrastructure, revising the revenue-sharing model, ensuring the Aave DAO retains significant control, and improving communication and transparency with the community. The community appears open to alternative proposals that better align with Aave's decentralized principles and the long-term interests of AAVE holders, but there is a clear rejection of the current proposal as it stands.`,
          keyPoints: analysis.keyPoints.length > 0 ? analysis.keyPoints : [
            "The proposed token launch is seen as unnecessary and potentially harmful to the Aave token and community.",
            "The revenue-sharing model is perceived as frontloaded and unfair, favoring early years when adoption and revenue may be low.",
            "There is a desire to maintain the Aave token as the primary governance and utility token for the ecosystem."
          ],
          concerns: analysis.concerns.length > 0 ? analysis.concerns : [
            "Dilution of the Aave token's value and attention.",
            "Misalignment of incentives with the proposed revenue-sharing model.",
            "Creation of a separate entity that could compete with the Aave ecosystem.",
            "Lack of transparency and community involvement in the decision-making process."
          ],
          sources: {
            discord: discordMessages.length > 0,
            twitter: twitterTweets.length > 0
          }
        };
        
        return sentimentAnalysis;
      } catch (error) {
        console.error(`Error analyzing sentiment for proposal ${proposalId}:`, error);
        throw error;
      }
    } 
  • API client method that wraps the sentiment service call and formats the result as a standard Response object with success/data or error.
    async getProposalSentimentAnalysis(proposalId: string): Promise<Response> {
      try {
        // In a production setting, this would call an API endpoint
        // For now, we'll directly use our sentiment analysis service
        const sentimentAnalysis = await getProposalSentimentAnalysis(proposalId);
        
        return {
          success: true,
          data: sentimentAnalysis
        };
      } catch (error: any) {
        return {
          success: false,
          error: error.message || `Failed to get sentiment analysis for proposal: ${proposalId}`
        };
      }
    }
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions the tool performs sentiment analysis using Discord and Twitter data, but doesn't describe key behaviors: what the sentiment output looks like (e.g., scores, categories), whether it's a read-only operation, potential rate limits, data freshness, or error handling. For a tool with no annotations, this leaves significant gaps in understanding its operational traits.

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 a single, clear sentence that efficiently conveys the core functionality without unnecessary words. It's front-loaded with the main action and resource, making it easy to parse. Every part of the sentence earns its place by specifying the tool's purpose and data sources.

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

Completeness2/5

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

Given the complexity of sentiment analysis and the lack of annotations and output schema, the description is incomplete. It doesn't explain what the tool returns (e.g., sentiment scores, aggregated metrics, or raw data), how the analysis is performed, or any limitations. For a tool that likely outputs structured sentiment data, this omission makes it hard for an agent to use effectively without additional context.

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?

The input schema has 100% description coverage, with 'proposalId' documented as 'The ID of the proposal to analyze.' The description doesn't add any parameter-specific details beyond this, such as format examples or constraints. Since the schema already provides adequate parameter information, the baseline score of 3 is appropriate, as the description doesn't compensate but also doesn't detract.

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 purpose: 'Get sentiment analysis for a specific proposal based on Discord and Twitter data.' It specifies the verb ('Get sentiment analysis'), resource ('specific proposal'), and data sources ('Discord and Twitter data'). However, it doesn't explicitly differentiate from sibling tools like 'getProposal' or 'getProposals,' which might also retrieve proposal information but without sentiment analysis.

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 doesn't mention prerequisites, such as needing a valid proposal ID, or contrast it with siblings like 'getProposal' (which might fetch basic proposal details) or 'getProposals' (which might list multiple proposals). There's no explicit when-to-use or when-not-to-use context.

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/tanmay4l/FutarchyMCPServer'

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