Skip to main content
Glama
matthewdtowles

iwantmymtg-mcp

get_portfolio_history

Retrieve the historical value of your portfolio over a specified number of days. Access requires a premium API key.

Instructions

Get portfolio value history. Premium-gated - free tier receives 403. Requires IWMM_API_KEY.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
daysNoHow many days of history. Server default applies if omitted.

Implementation Reference

  • The handler function for the get_portfolio_history tool. It takes an optional 'days' parameter (1-3650) and makes an authenticated GET request to /api/v1/portfolio/history. This is the core execution logic.
    export const getPortfolioHistoryTool = {
      name: "get_portfolio_history",
      description:
        "Get portfolio value history. Premium-gated - free tier receives 403. Requires IWMM_API_KEY.",
      inputSchema: z.object({
        days: z.number().int().min(1).max(3650).optional().describe("How many days of history. Server default applies if omitted."),
      }),
      handler: ({ days }: { days?: number }) =>
        apiFetch({ path: "/api/v1/portfolio/history", query: { days }, authenticated: true }),
    };
  • Input validation schema using Zod. Accepts an optional 'days' parameter (integer, 1-3650) that specifies how many days of history to retrieve.
    inputSchema: z.object({
      days: z.number().int().min(1).max(3650).optional().describe("How many days of history. Server default applies if omitted."),
  • The tool is imported from './portfolio.js' and registered in the tools array at line 72 of src/tools/index.ts. It is listed in the 'Portfolio (auth; most are Premium-gated)' section.
      getPortfolioHistoryTool,
      getCardPerformanceTool,
      getCashFlowTool,
      getRealizedGainsTool,
      getPortfolioBreakdownTool,
      refreshPortfolioTool,
    } from "./portfolio.js";
    import {
      listAlertsTool,
      createAlertTool,
      updateAlertTool,
      deleteAlertTool,
    } from "./alerts.js";
    import {
      listNotificationsTool,
      getUnreadCountTool,
      markNotificationReadTool,
      markAllNotificationsReadTool,
    } from "./notifications.js";
    
    export interface ToolDefinition {
      name: string;
      description: string;
      inputSchema: z.ZodTypeAny;
      handler: (input: any) => Promise<unknown>;
    }
    
    export const tools: ToolDefinition[] = [
      // Read-only (no auth)
      searchCardsTool,
      getCardTool,
      getCardPricesTool,
      getCardPriceHistoryTool,
      searchSetsTool,
      getSetTool,
      listSetCardsTool,
      getSealedProductsTool,
      // Inventory (auth)
      listInventoryTool,
      getInventoryQuantitiesTool,
      addInventoryTool,
      updateInventoryTool,
      removeInventoryTool,
      // Transactions (auth)
      listTransactionsTool,
      recordTransactionTool,
      updateTransactionTool,
      deleteTransactionTool,
      getCostBasisTool,
      // Portfolio (auth; most are Premium-gated)
      getPortfolioSummaryTool,
      getPortfolioHistoryTool,
  • The tools array is converted to a name-indexed lookup map (toolsByName) which the server uses to dispatch tool calls by name.
    export const toolsByName: Record<string, ToolDefinition> = Object.fromEntries(
  • The apiFetch helper function used by the handler to make the actual HTTP request to the external IWMM API. It constructs the URL with query params, adds auth headers, and handles errors.
    export async function apiFetch<T = unknown>(req: ApiRequest): Promise<T> {
      const url = new URL(req.path, config.baseUrl);
      if (req.query) {
        for (const [k, v] of Object.entries(req.query)) {
          if (v !== undefined && v !== null && v !== "") {
            url.searchParams.set(k, String(v));
          }
        }
      }
    
      const headers: Record<string, string> = {
        Accept: "application/json",
        "User-Agent": "iwantmymtg-mcp/0.0.1",
      };
    
      if (req.authenticated) {
        const { requireApiKey } = await import("./config.js");
        headers["Authorization"] = `Bearer ${requireApiKey()}`;
      }
    
      if (req.body !== undefined) {
        headers["Content-Type"] = "application/json";
      }
    
      const res = await fetch(url, {
        method: req.method ?? "GET",
        headers,
        body: req.body !== undefined ? JSON.stringify(req.body) : undefined,
      });
    
      if (!res.ok) {
        const text = await res.text();
        throw new ApiError(res.status, text, {
          limit: res.headers.get("X-RateLimit-Limit") ?? undefined,
          remaining: res.headers.get("X-RateLimit-Remaining") ?? undefined,
          reset: res.headers.get("X-RateLimit-Reset") ?? undefined,
        });
      }
    
      if (res.status === 204) return undefined as T;
      return (await res.json()) as T;
    }
Behavior3/5

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

With no annotations, the description adds some transparency by disclosing premium-gated access and 403 errors for free tier. However, it does not describe side effects (likely none) or return format/pagination, leaving gaps in behavioral understanding.

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?

Two concise sentences with no wasted words. The first sentence states the purpose, the second adds critical constraints. Every sentence earns its place.

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?

The description covers authentication and premium requirements adequately given one optional parameter and no output schema. However, it does not describe what the output contains (e.g., list of values with dates), which would be helpful for completeness.

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 for the single parameter 'days,' so the tool description does not need to add more. The description adds no extra meaning beyond the schema's own description of the parameter. Baseline 3 applies.

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 verb 'Get' and resource 'portfolio value history,' which is specific. However, it does not explicitly differentiate from sibling tools like get_portfolio_breakdown or get_portfolio_summary, leaving some ambiguity about the exact nature of 'history.'

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 mentions premium gating and API key requirement, which are prerequisites, but provides no guidance on when to use this tool versus alternatives such as get_portfolio_summary or get_card_price_history. No exclusions or context for selection.

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/matthewdtowles/iwantmymtg-mcp'

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