Skip to main content
Glama
MAG-Cie

MCP for Microsoft To Do

list_all_tasks

Read-only

Retrieve all active tasks from every list in one request, avoiding multiple list-specific calls.

Instructions

Fetch every active task across every list in a single round-trip (uses Graph $batch internally). Use this for the question "what are all my tasks?" instead of N×list_tasks calls. Optional filter is an OData filter applied per list (e.g. "importance eq 'high'"). By default status ne 'completed' is appended unless include_completed is true.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filterNo
top_per_listNo
include_completedNo
verboseNoIf true: returns full JSON. Otherwise: compact text format (default, saves tokens).

Implementation Reference

  • The main handler function for the 'list_all_tasks' tool. Fetches all lists via listTaskLists(), builds a filter (appending 'status ne completed' unless includeCompleted), then calls fetchTasksAcrossLists() to get tasks from each list in parallel or via batch. Returns ListWithTasks[] with list metadata, tasks, and optional errors per list.
    export async function listAllTasks(
      opts: {
        filter?: string;
        topPerList?: number;
        includeCompleted?: boolean;
      } = {}
    ): Promise<ListWithTasks[]> {
      const lists = await listTaskLists();
      const filterParts: string[] = [];
      if (opts.filter) filterParts.push(opts.filter);
      if (!opts.includeCompleted) filterParts.push("status ne 'completed'");
      const filter = filterParts.length > 0 ? filterParts.join(" and ") : undefined;
      const perList = await fetchTasksAcrossLists(lists, {
        filter,
        top: opts.topPerList ?? 50,
      });
      return perList.map((r) => ({
        list: { id: r.list.id, displayName: r.list.displayName },
        tasks: r.tasks,
        error: r.error,
      }));
    }
  • Helper function fetchTasksAcrossLists() that either parallelizes direct calls (for <=5 lists) or uses a single Graph $batch call (for >5 lists) to fetch tasks from multiple lists efficiently.
    async function fetchTasksAcrossLists(
      lists: TodoTaskList[],
      opts: { filter?: string; top?: number } = {}
    ): Promise<Array<{ list: TodoTaskList; tasks: TodoTask[]; error?: string }>> {
      const top = opts.top ?? 25;
    
      // Few lists: just parallelize direct calls (low HTTP overhead, MSAL refresh once)
      if (lists.length <= PARALLEL_THRESHOLD) {
        return Promise.all(
          lists.map(async (list) => {
            try {
              const tasks = await listTasks(list.id, { filter: opts.filter, top });
              return { list, tasks };
            } catch (err: any) {
              return { list, tasks: [] as TodoTask[], error: err.message ?? String(err) };
            }
          })
        );
      }
    
      // Many lists: 1 HTTP call via $batch (still chunked by 20 internally)
      // No $select: rejected by Graph on tasks collection for personal accounts.
      const qs = buildOData({
        filter: opts.filter,
        top,
      });
      const requests: BatchRequest[] = lists.map((list, idx) => ({
        id: String(idx),
        method: "GET",
        url: `/me/todo/lists/${enc(list.id)}/tasks${qs}`,
      }));
      const responses = await graphBatch(requests);
      const results: Array<{ list: TodoTaskList; tasks: TodoTask[]; error?: string }> = new Array(
        lists.length
      );
      for (const r of responses) {
        const idx = Number(r.id);
        if (r.status >= 200 && r.status < 300) {
          const body = r.body as GraphCollection<TodoTask>;
          results[idx] = { list: lists[idx], tasks: body.value ?? [] };
        } else {
          const body = r.body as GraphErrorBody | undefined;
          const err = body?.error
            ? `${body.error.code ?? r.status}: ${body.error.message ?? "(no message)"}`
            : `HTTP ${r.status}`;
          results[idx] = { list: lists[idx], tasks: [], error: err };
        }
      }
      return results;
    }
  • Zod schema for the list_all_tasks tool input: optional filter (OData string), top_per_list (int, max 200), include_completed (boolean), and a verbose field.
    list_all_tasks: z.object({
      filter: z.string().optional(),
      top_per_list: z.number().int().positive().max(200).optional(),
      include_completed: z.boolean().optional(),
      ...verboseField,
    }),
  • src/index.ts:646-658 (registration)
    Tool registration with name 'list_all_tasks', description explaining it uses Graph $batch internally, and JSON Schema input definition (filter, top_per_list, include_completed).
      name: "list_all_tasks",
      description:
        "Fetch every active task across every list in a single round-trip (uses Graph $batch internally). Use this for the question \"what are all my tasks?\" instead of N×list_tasks calls. Optional `filter` is an OData filter applied per list (e.g. \"importance eq 'high'\"). By default `status ne 'completed'` is appended unless `include_completed` is true.",
      inputSchema: {
        type: "object",
        properties: {
          filter: { type: "string" },
          top_per_list: { type: "number" },
          include_completed: { type: "boolean" },
          ...verboseJsonProp,
        },
      },
    },
  • Formatting helper that converts ListWithTasks[] into a compact human-readable string for the tool output, listing each list's name and its tasks.
    export function formatAllTasksCompact(perList: ListWithTasks[]): string {
      const total = perList.reduce((s, l) => s + l.tasks.length, 0);
      const lines: string[] = [t.allTasksHeader(perList.length, total)];
      for (const { list, tasks, error } of perList) {
        if (error) {
          lines.push(`\n${JSON.stringify(list.displayName)} (${list.id}) — ${t.error(error)}`);
          continue;
        }
        if (tasks.length === 0) continue;
        lines.push(`\n${JSON.stringify(list.displayName)} (${list.id}) — ${tasks.length}:`);
        for (const task of tasks) lines.push(`  ${formatTaskCompact(task)}`);
      }
      return lines.join("\n");
    }
  • ListWithTasks interface: the return type containing list metadata (id, displayName), tasks array, and optional error string.
    export interface ListWithTasks {
      list: { id: string; displayName: string };
      tasks: TodoTask[];
      error?: string;
    }
Behavior4/5

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

Discloses internal use of Graph $batch, default exclusion of completed tasks, and conditional inclusion. Annotations already indicate read-only and open-world; description adds significant behavioral context beyond annotations.

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 sentences, no redundancy. First sentence states purpose and internal detail, second provides usage guidance and parameter behavior.

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?

Covers main purpose, filter usage, and default behavior. However, misses explanation of top_per_list and output format (no output schema), and does not address when to use versus other list/search siblings.

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?

Describes filter as OData and default include_completed behavior, but top_per_list is not explained. Schema coverage is low (25%), so description partially compensates but leaves a gap.

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?

Clearly states it fetches every active task across all lists in a single round-trip, distinguishing it from multiple list_tasks calls. The verb 'Fetch' and resource 'every active task across every list' are specific.

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

Usage Guidelines4/5

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

Explicitly says to use for 'what are all my tasks?' instead of N×list_tasks, and explains default filtering behavior. Does not list all alternatives but provides clear 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/MAG-Cie/mcp-microsoft-todo'

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