AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Microsoft Planner Mcp

mcp-aixolotl-microsoft-planner-mcp · by aixolotl

Unofficial MCP server for Microsoft Planner using Microsoft Graph and Entra ID delegated authentication

No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add mcp-aixolotl-microsoft-planner-mcp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-aixolotl-microsoft-planner-mcp)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Microsoft Planner Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

MCP Server for Microsoft Planner

An unofficial MCP server that connects AI assistants to Microsoft Planner. Ask your AI assistant to create tasks, organise plans, manage buckets, and more, all through natural language.

> This is an unofficial, community/open-source MCP server for Microsoft Planner. > It is not affiliated with, endorsed by, or sponsored by Microsoft.

Built with FastMCP and authenticated via Microsoft Entra ID (Azure AD) using the On-Behalf-Of (OBO) flow to call Microsoft Graph.

Table of Contents

  • [What Can It Do?](#what-can-it-do)
  • [Prerequisites](#prerequisites)
  • [Azure Entra ID Setup](#azure-entra-id-setup)
  • [Installation](#installation)
  • [Configuration](#configuration)
  • [Running the Server](#running-the-server)
  • [Connecting an MCP Client](#connecting-an-mcp-client)
  • [Available Tools](#available-tools)
  • [Development](#development)
  • [Contributing](#contributing)
  • [License](#license)
  • [Security](#security)

What Can It Do?

Once connected, you can ask your AI assistant things like:

  • "Show me all my Planner tasks that are overdue"
  • "Create a task called 'Prepare Q3 report' in the Marketing plan"
  • "Move all incomplete tasks in the Sprint bucket to the Backlog bucket"
  • "Mark the 'Update docs' task as complete"

The AI assistant translates your request into the appropriate tool calls automatically.

Note: This MCP only supports Planner basic tasks and plans

Prerequisites

  • A Microsoft 365 account with access to Microsoft Planner
  • An Azure Entra ID (Azure AD) app registration (see [Azure Setup](#azure-entra-id-setup) below)
  • An MCP-compatible client — for example:
  • VS Code
  • Claude Desktop

To run the server locally you also need:

Or, to run via Docker:

Azure Entra ID Setup

An Azure app registration is required so the server can authenticate users and call Microsoft Graph on their behalf. You need admin access to an Azure Entra ID tenant (or ask your IT administrator).

Step 1 — Register the Application

  1. Go to the Azure PortalMicrosoft Entra IDApp registrationsNew registration
  2. Enter a name (e.g. Microsoft Planner MCP)
  3. Under Supported account types, choose the option appropriate for your organisation
  4. Set the Redirect URI to Webhttp://localhost:8000/auth/callback
  5. Click Register

Step 2 — Configure API Permissions

  1. In your new app registration, go to API permissionsAdd a permissionMicrosoft GraphDelegated permissions
  2. Add these permissions:
  • Tasks.ReadWrite — read and write Planner tasks
  • User.Read — read the signed-in user's profile
  • User.ReadBasic.All — resolve user display names from the GUIDs in task assignments (required only for list_users tool)
  1. Click Grant admin consent for your organisation

Step 3 — Expose an API Scope

  1. Go to Expose an API
  2. Set the Application ID URI (accept the default api:// or customise it)
  3. Click Add a scope:
  • Scope name: mcp-access
  • Who can consent: Admins and users (or Admins only if you prefer)
  • Fill in the display name and description
  • Set state to Enabled

Step 4 — Set Token Version

  1. Go to Manifest (or AuthenticationAdvanced settings in newer portal versions)
  2. Set "requestedAccessTokenVersion" to 2
  3. Save

Step 5 — Create a Client Secret

  1. Go to Certificates & secretsNew client secret
  2. Add a description and choose an expiry period
  3. Copy the Value immediately (it is only shown once)

Step 6 — Note Your IDs

You will need these three values for configuration:

| Value | Where to Find It | |---|---| | Application (client) ID | App registration → Overview | | Directory (tenant) ID | App registration → Overview | | Client secret | The value copied in Step 5 |

Installation

Option A — Local (Python + uv)

git clone https://github.com/aixolotl/microsoft-planner-mcp
cd microsoft-planner-mcp
uv sync

Option B — Docker

No Python installation needed. See [Running with Docker](#running-with-docker) below.

Configuration

Copy the example environment file and fill in your Azure credentials:

cp .env.example .env

Edit .env:

# Azure App Registration (required)
CLIENT_ID=your-app-client-id
CLIENT_SECRET=your-app-client-secret
TENANT_ID=your-azure-tenant-id

# Public URL of this server (used for OAuth redirect URI)
BASE_URL=http://localhost:8000

# JSON-encoded list of allowed CORS origins
# Include http://localhost:6274 if using MCP Inspector for testing
ALLOWED_ORIGINS=["http://localhost:8000","http://localhost:6274"]

# Require FastMCP's extra client consent prompt per MCP client. (default: true)
# Prevents confused-deputy attacks by requiring users to explicitly approve each new
# client. Keep true in production; set false only for local dev with throwaway
# clients.
# REQUIRE_AUTHORIZATION_CONSENT=true

# Optional rate-limit overrides (per client sliding window)
# Defaults are 120 requests per 1 minute
# RATE_LIMIT_MAX_REQUESTS=120
# RATE_LIMIT_WINDOW_MINUTES=1

REQUIRE_AUTHORIZATION_CONSENT controls whether FastMCP prompts users to explicitly approve each new MCP client. Keep this true (default) in production to prevent confused-deputy attacks; set it to false only during local development with throwaway clients.

RATE_LIMIT_MAX_REQUESTS and RATE_LIMIT_WINDOW_MINUTES are optional and should stay commented out unless you need to override the defaults for your environment.

Running the Server

Local

uv run uvicorn src.server:app --host 0.0.0.0 --port 8000

The MCP endpoint is available at http://localhost:8000/mcp. A health check endpoint is at http://localhost:8000/health.

Running with Docker

# Pull the latest image
docker pull ghcr.io/aixolotl/microsoft-planner-mcp:latest

# Run with environment variables
docker run --rm -i \
  -e BASE_URL=https://localhost:8000 \
  -e CLIENT_ID=your_client_id \
  -e CLIENT_SECRET=your_api_token \
  -e TENANT_ID=your_tenant_id \
  -e ALLOWED_ORIGINS=["http://localhost:8000","http://localhost:6274", "http://localhost:3000"] \
  -e REQUIRE_AUTHORIZATION_CONSENT=true \
  ghcr.io/aixolotl/microsoft-planner-mcp:latest

This starts the MCP server on port 8000. To override rate limits, also pass -e RATE_LIMIT_MAX_REQUESTS= and -e RATE_LIMIT_WINDOW_MINUTES= (defaults: 120 and 1).

Running with Docker compose

docker compose up

This starts the MCP server on port 8000. The Docker Compose configuration also includes a Jaeger instance for trace visualisation (see [OpenTelemetry Tracing](#opentelemetry-tracing)).

Connecting an MCP Client

Once the server is running, configure your MCP client to connect to it.

VS Code

Add the following to your VS Code settings (.vscode/settings.json in your project, or your user settings):

{
  "mcp": {
    "servers": {
      "planner": {
        "type": "http",
        "url": "http://localhost:8000/mcp"
      }
    }
  }
}

Then use Copilot Chat in Agent mode and ask it to interact with your Planner tasks. Copilot will discover the available tools automatically.

Other MCP Clients

Any client that supports the Streamable HTTP transport can connect by pointing to http://localhost:8000/mcp. The server advertises OAuth metadata automatically — the client handles the authentication flow.

Available Tools

All tools are available to your AI assistant automatically once connected. You don't need to call them directly — just describe what you want in natural language. The parameter details below are provided for reference and for client developers.

Read-only tools are annotated with readOnlyHint: true so clients can skip confirmation prompts. Destructive tools (deletes) are annotated with destructiveHint: true.

User

get_me

Return the authenticated user's profile from Microsoft Graph.

  • Parameters: None
  • Returns: User profile object (id, displayName, mail, etc.) or null
list_users

Retrieve Microsoft 365 users by GUID, e-mail address, or free-text search. Useful for resolving the user GUIDs returned in task assignment objects to display names.

| Parameter | Type | Required | Description | |---|---|---|---| | select | string | No | Comma-separated fields to include (default: id,displayName,mail,userPrincipalName). Pass *all for all fields. | | search | string | No | Free text search on display name, or search by field name and value, e.g. Alice or surname:Smith | | guids | list[string] | No | User object GUIDs to look up. Translated to an OData $filter expression. | | emails | list[string] | No | User principal names (UPNs / e-mail addresses) to look up. Translated to an OData $filter expression. | | top | integer | No | Maximum number of users to return (default: 10). Ignored when guids or emails are provided. |

  • Returns: List of user objects or null

> Note: When both guids/emails and search are supplied, the GUID/email filter takes priority. Very large lists of GUIDs or e-mail addresses are silently truncated to stay within the 2 048-character Graph URL limit.

Groups

list_my_groups

List all Microsoft 365 groups the authenticated user is a member of.

| Parameter | Type | Required | Description | |---|---|---|---| | select | string | No | Comma-separated fields to include (default: id,displayName,mail). Pass *all for all fields. | | filter | string | No | OData filter expression, e.g. startsWith(displayName,'Project') | | search | string | No | OData search string, e.g. "displayName:Project" |

  • Returns: List of group objects or null

> Note: The Groups tool will not return details like name or mail of groups with the standard permissions Tasks.ReadWrite documented here, however searching and filtering still works, so you can find a group with a specific name using this tool.

Plans

list_my_plans

List Planner plans shared with the authenticated user.

| Parameter | Type | Required | Description | |---|---|---|---| | select | string | No | Comma-separated fields to include (default: id,title,owner,createdBy,createdDateTime). Pass *all for all fields. |

  • Returns: List of plan objects or null
list_group_plans

List all Planner plans belonging to a Microsoft 365 group.

| Parameter | Type | Required | Description | |---|---|---|---| | groupId | string | Yes | The object ID of the group (from list_my_groups) | | select | string | No | Comma-separated fields to include (default: id,title,owner,createdBy,createdDateTime). Pass *all for all fields. |

  • Returns: List of plan objects or null
create_plan

Create a new Planner plan for a Microsoft 365 group.

| Parameter | Type | Required | Description | |---|---|---|---| | groupId | string | Yes | The object ID of the M365 group that will own the plan | | title | string | Yes | Display title for the new plan |

  • Returns: The created plan object or null
delete_plan

Delete a Planner plan.

| Parameter | Type | Required | Description | |---|---|---|---| | planId | string | Yes | The ID of the plan to delete | | etag | string | Yes | The current @odata.etag of the plan (retries once if stale) |

  • Returns: Confirmation message
list_plan_categories

Get category label definitions for a Planner plan. Returns all 25 category slots with their key (e.g. category1) and display name.

| Parameter | Type | Required | Description | |---|---|---|---| | planId | string | Yes | The ID of the plan |

  • Returns: List of category objects (key, display_name) or null

Buckets

list_buckets

List all buckets in a Planner plan.

| Parameter | Type | Required | Description | |---|---|---|---| | planId | string | Yes | The ID of the plan |

  • Returns: List of bucket objects or null
create_bucket

Create a new bucket in a Planner plan.

| Parameter | Type | Required | Description | |---|---|---|---| | planId | string | Yes | The ID of the plan to create the bucket in | | name | string | Yes | Display name for the new bucket |

  • Returns: The created bucket object or null
delete_bucket

Delete a Planner bucket.

| Parameter | Type | Required | Description | |---|---|---|---| | bucketId | string | Yes | The ID of the bucket to delete | | etag | string | Yes | The current @odata.etag of the bucket (retries once if stale) |

  • Returns: Confirmation message

Tasks

list_my_tasks

List all Planner tasks assigned to the authenticated user across all plans.

| Parameter | Type | Required | Description | |---|---|---|---| | select | string | No | Comma-separated fields to include (default: *all). Pass *all for all fields. | | filter | string | No | OData filter expression, e.g. percentComplete ne 100 | | search | string | No | Free-text search matched against the task title |

  • Returns: List of task objects or null
list_tasks

List all tasks in a Planner plan.

| Parameter | Type | Required | Description | |---|---|---|---| | planId | string | Yes | The ID of the plan | | select | string | No | Comma-separated fields to include (default: *all). Pass *all for all fields. | | filter | string | No | OData filter expression, e.g. percentComplete eq 0 | | search | string | No | Free-text search matched against the task title |

  • Returns: List of task objects or null
get_task_details

Get the full details for a task: description, checklist items, and external references.

| Parameter | Type | Required | Description | |---|---|---|---| | taskId | string | Yes | The ID of the task |

  • Returns: Task details object (description, checklist, references) or null
create_task

Create a new task in a Planner plan.

| Parameter | Type | Required | Description | |---|---|---|---| | planId | string | Yes | The ID of the plan | | bucketId | string | Yes | The ID of the bucket to place the task in | | title | string | Yes | Title of the task | | startDateTime | string | No | ISO 8601 start date (e.g. 2026-05-01T00:00:00) | | dueDateTime | string | No | ISO 8601 due date (e.g. 2026-05-31T00:00:00) | | percentComplete | integer | No | Completion percentage, 0–100 | | assignUserIds | list[string] | No | User object IDs to assign to the task |

  • Returns: The created task object or null
update_task

Update a task's standard fields and/or detail fields (description, checklist, references). Only provided fields are changed. When detail fields are specified, a separate API call updates the task details resource automatically.

| Parameter | Type | Required | Description | |---|---|---|---| | taskId | string | Yes | The ID of the task | | etag | string | Yes | The current @odata.etag of the task (retries once if stale) | | title | string | No | New title | | percentComplete | integer | No | Completion percentage, 0–100 | | dueDateTime | string | No | ISO 8601 due date | | bucketId | string | No | ID of the bucket to move the task to | | priority | integer | No | Priority 0 (urgent)–10 (low). Planner maps: 1=urgent, 3=important, 5=medium, 9=low | | `assignee

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.