Skip to main content
Glama

getLighthousePortfolio

Fetch and display a detailed summary of your Lighthouse crypto portfolio, including asset type breakdowns and major holdings, for informed decision-making.

Instructions

Fetch and display a detailed summary of a Lighthouse portfolio with breakdown by asset types and major holdings.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
portfolioNoOptional portfolio name to select a specific portfolio to display a summary for

Implementation Reference

  • index.ts:99-227 (registration)
    Registration of the 'getLighthousePortfolio' tool using server.addTool, including name, description, Zod schema for parameters, and the execute handler function.
    server.addTool({
      name: "getLighthousePortfolio",
      description:
        "Fetch and display a detailed summary of a Lighthouse portfolio with breakdown by asset types and major holdings.",
      parameters: z.object({
        portfolio: z
          .string()
          .optional()
          .describe(
            "Optional portfolio name to select a specific portfolio to display a summary for"
          ),
      }),
      execute: async (args) => {
        try {
          if (!lighthouse.isAuthenticated()) {
            return {
              content: [
                {
                  type: "text",
                  text: "No session cookie available. Please authenticate first.",
                },
              ],
            };
          }
    
          // Find the portfolio
          const portfolio = await lighthouse.findPortfolio(args.portfolio);
    
          // Get the portfolio data
          const data = await lighthouse.getPortfolioData(portfolio.slug);
    
          // Calculate total USD value
          const totalUsdValue = data.usdValue;
    
          // Get wallets/accounts
          const wallets = Object.values(data.accounts).map((account: Account) => ({
            id: account.id,
            name: account.name,
            type: account.type,
          }));
    
          // Calculate asset type breakdown
          const assetTypeMap = new Map<string, number>();
    
          data.positions.forEach((position: Position) => {
            position.assets.forEach((asset: LighthouseAsset) => {
              const currentValue = assetTypeMap.get(asset.type) || 0;
              assetTypeMap.set(asset.type, currentValue + asset.usdValue);
            });
          });
    
          // Convert to array and sort by value
          const assetTypeBreakdown = Array.from(assetTypeMap.entries())
            .map(([type, value]) => ({
              type,
              value,
              percentage: (value / totalUsdValue) * 100,
            }))
            .sort((a, b) => b.value - a.value);
    
          // Get major assets (>= $1000)
          const majorAssets = data.positions
            .flatMap((position) =>
              position.assets
                .filter((asset) => asset.usdValue >= 1000)
                .map((asset) => ({
                  name: asset.name,
                  symbol: asset.symbol,
                  value: asset.usdValue,
                  amount: asset.amount,
                }))
            )
            .sort((a, b) => b.value - a.value);
    
          // Format the response
          const assetTypeTable = `
    | Asset Type | Net Value | % of Portfolio |
    |------------|-----------|----------------|
    ${assetTypeBreakdown
      .map(
        (item) =>
          `| ${item.type} | $${formatNumber(item.value)} | ${formatPercentage(
            item.percentage
          )}% |`
      )
      .join("\n")}
    `;
    
          const assetsTable = `
    | Asset | Value | Amount |
    |-------|-------|--------|
    ${majorAssets
      .map(
        (asset) =>
          `| ${asset.name} (${asset.symbol}) | $${formatNumber(
            asset.value
          )} | ${formatNumber(asset.amount)} |`
      )
      .join("\n")}
    `;
    
          return {
            content: [
              {
                type: "text",
                text: `# Lighthouse Portfolio Summary: ${
                  portfolio.name
                }\n\n## Total Portfolio Value: $${formatNumber(
                  totalUsdValue
                )}\n\n## Wallets (${wallets.length}):\n${wallets
                  .map((w) => `- ${w.name} (${w.type})`)
                  .join(
                    "\n"
                  )}\n\n## Asset Type Breakdown:\n${assetTypeTable}\n\n## Major Holdings (>= $1,000):\n${assetsTable}`,
              },
            ],
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: "text",
                text: `Failed to fetch Lighthouse portfolio: ${error.message}`,
              },
            ],
          };
        }
      },
    });
  • The execute handler that implements the core logic: authenticates, fetches portfolio data using lighthouse client, computes asset breakdowns and major holdings, formats tables, and returns markdown summary.
      execute: async (args) => {
        try {
          if (!lighthouse.isAuthenticated()) {
            return {
              content: [
                {
                  type: "text",
                  text: "No session cookie available. Please authenticate first.",
                },
              ],
            };
          }
    
          // Find the portfolio
          const portfolio = await lighthouse.findPortfolio(args.portfolio);
    
          // Get the portfolio data
          const data = await lighthouse.getPortfolioData(portfolio.slug);
    
          // Calculate total USD value
          const totalUsdValue = data.usdValue;
    
          // Get wallets/accounts
          const wallets = Object.values(data.accounts).map((account: Account) => ({
            id: account.id,
            name: account.name,
            type: account.type,
          }));
    
          // Calculate asset type breakdown
          const assetTypeMap = new Map<string, number>();
    
          data.positions.forEach((position: Position) => {
            position.assets.forEach((asset: LighthouseAsset) => {
              const currentValue = assetTypeMap.get(asset.type) || 0;
              assetTypeMap.set(asset.type, currentValue + asset.usdValue);
            });
          });
    
          // Convert to array and sort by value
          const assetTypeBreakdown = Array.from(assetTypeMap.entries())
            .map(([type, value]) => ({
              type,
              value,
              percentage: (value / totalUsdValue) * 100,
            }))
            .sort((a, b) => b.value - a.value);
    
          // Get major assets (>= $1000)
          const majorAssets = data.positions
            .flatMap((position) =>
              position.assets
                .filter((asset) => asset.usdValue >= 1000)
                .map((asset) => ({
                  name: asset.name,
                  symbol: asset.symbol,
                  value: asset.usdValue,
                  amount: asset.amount,
                }))
            )
            .sort((a, b) => b.value - a.value);
    
          // Format the response
          const assetTypeTable = `
    | Asset Type | Net Value | % of Portfolio |
    |------------|-----------|----------------|
    ${assetTypeBreakdown
      .map(
        (item) =>
          `| ${item.type} | $${formatNumber(item.value)} | ${formatPercentage(
            item.percentage
          )}% |`
      )
      .join("\n")}
    `;
    
          const assetsTable = `
    | Asset | Value | Amount |
    |-------|-------|--------|
    ${majorAssets
      .map(
        (asset) =>
          `| ${asset.name} (${asset.symbol}) | $${formatNumber(
            asset.value
          )} | ${formatNumber(asset.amount)} |`
      )
      .join("\n")}
    `;
    
          return {
            content: [
              {
                type: "text",
                text: `# Lighthouse Portfolio Summary: ${
                  portfolio.name
                }\n\n## Total Portfolio Value: $${formatNumber(
                  totalUsdValue
                )}\n\n## Wallets (${wallets.length}):\n${wallets
                  .map((w) => `- ${w.name} (${w.type})`)
                  .join(
                    "\n"
                  )}\n\n## Asset Type Breakdown:\n${assetTypeTable}\n\n## Major Holdings (>= $1,000):\n${assetsTable}`,
              },
            ],
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: "text",
                text: `Failed to fetch Lighthouse portfolio: ${error.message}`,
              },
            ],
          };
        }
      },
  • Zod schema defining the input parameters for the tool, with an optional 'portfolio' string.
    parameters: z.object({
      portfolio: z
        .string()
        .optional()
        .describe(
          "Optional portfolio name to select a specific portfolio to display a summary for"
        ),
    }),
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 states the tool fetches and displays data, implying a read-only operation, but doesn't address key aspects like authentication requirements, rate limits, error conditions, or response format. The description lacks details on what 'detailed summary' entails beyond asset types and holdings, leaving behavioral traits unclear.

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, well-structured sentence that efficiently conveys the core action and output. It avoids redundancy and front-loads key information. However, it could be slightly more concise by merging 'fetch and display' into a single verb like 'retrieve', but this is minor.

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 no annotations and no output schema, the description is incomplete for a tool that fetches detailed data. It mentions 'detailed summary' but doesn't specify what that includes beyond asset types and holdings, leaving gaps in understanding the return value. For a read operation with potential complexity, more context on output structure or behavior is needed.

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%, with the single parameter 'portfolio' documented as an optional string for selecting a specific portfolio. The description adds no additional parameter semantics beyond what the schema provides, such as default behavior if omitted or examples of portfolio names. Baseline score of 3 is appropriate since the schema adequately covers the parameter.

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 with specific verbs ('fetch and display') and resources ('detailed summary of a Lighthouse portfolio'), including what information is provided ('breakdown by asset types and major holdings'). It distinguishes from siblings like 'listLighthousePortfolios' by focusing on detailed summaries rather than listing portfolio names. However, it doesn't explicitly contrast with performance or yield data tools, preventing a perfect score.

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 like 'getLighthousePerformanceData' or 'getLighthouseYieldData'. It mentions fetching a 'detailed summary' but doesn't clarify if this should be used for overviews versus those tools for specific metrics. No prerequisites, exclusions, or explicit alternatives are stated.

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

Related 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/l3wi/mcp-lighthouse'

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