CAT
/MCP
SkillsMCPMarketplacesDigestToolsAdvertise

This week in Claude

Every Monday: Claude Code, Agent SDK, MCP, and the Anthropic platform moves worth your time.

Skills by Category
Frontend DevelopmentBackend & APIsTesting & QASecurityDevOps & CI/CDGit & Pull RequestsDocumentationCode Review & QualityAI & Agent BuildingSkill Development
MCP Servers by Category
Sales & MarketingWeb & Browser AutomationDatabasesAI & LLM ToolsCloud & InfrastructureCommunication & MessagingDeveloper ToolsDesign & CreativeDocuments & KnowledgeSearch & Web Crawling
Marketplaces by Category
AI Agents & OrchestrationLLM IntegrationDevelopment ToolsFrontend & UIBackend & APIsDatabasesTesting & Code QualityDevOps & CloudSecurity & ComplianceGit & Version Control

Cross AI Tools

Discover Claude Code plugins, extensions, and tools. Automatically updated directory of Anthropic Claude AI marketplaces with development tools, productivity plugins, and integrations.

Resources

  • Browse Skills
  • Browse MCP Servers
  • Browse Marketplaces
  • Plugins Reference

Community

  • About
  • Tools
  • Feedback
  • Privacy Policy
  • Advertise

Built for the Claude Code community with Claude Code by @mertduzgun

Independent project, not affiliated with Anthropic

Onplana

onplana/onplana-mcp-server
329 toolsauthHTTPregistry active
Summary

Connects Claude to Onplana's project portfolio management platform as an alternative to Microsoft Project Online. Supports OAuth and PAT authentication over streamable HTTP. The underlying codebase is a production-hardened TypeScript MCP server template that handles prompt injection containment, stateless Bearer auth, and plan-gate semantics. The repo includes both the server framework and a typed client SDK for calling Onplana's public MCP endpoint. Exposes tools for listing projects, searching organizational knowledge (hybrid semantic and lexical search across tasks, risks, goals, comments, wiki pages), and other PM operations. Reach for this if you're running a PMO and want Claude to query and manipulate project data programmatically, or if you're building your own MCP server and want a reference implementation with security primitives already solved.

CodeRabbit
CodeRabbit
AI writes the code. CodeRabbit catches the slop.
Try For Free →
Keep your Mac awake
Keep your Mac awake
Keep your Mac awake while Claude Code and 40+ AI agents run. Sleeps when they're idle.
One time payment $9 →
Context.devContext.dev
Context.dev
Integrate web data into your AI product. One API to scrape website & brand data.
Get API Key Now →
Make your agent a DeFi expert
Make your agent a DeFi expert
Agent, run crypto. Access onchain data & trade routes via 1inch.
Install now →
Make money from your Skills
Make money from your Skills
On Capafy, your Skill runs online 24/7 as an agent product, and you get paid every time someone uses it.
Start earning →
AppSignal
AppSignal
Monitor with ease. Code with confidence.
Start Free Trial →
CodeRabbit
CodeRabbit
AI writes the code. CodeRabbit catches the slop.
Try For Free →
Keep your Mac awake
Keep your Mac awake
Keep your Mac awake while Claude Code and 40+ AI agents run. Sleeps when they're idle.
One time payment $9 →
Context.devContext.dev
Context.dev
Integrate web data into your AI product. One API to scrape website & brand data.
Get API Key Now →
Make your agent a DeFi expert
Make your agent a DeFi expert
Agent, run crypto. Access onchain data & trade routes via 1inch.
Install now →
Make money from your Skills
Make money from your Skills
On Capafy, your Skill runs online 24/7 as an agent product, and you get paid every time someone uses it.
Start earning →
AppSignal
AppSignal
Monitor with ease. Code with confidence.
Start Free Trial →

Tools

Public tool metadata for what this MCP can expose to an agent.

29 tools
list_projectsList projects in the current organization. Use this to find a project by name before acting on it, or to give the user an overview of their work. Returns up to `limit` projects ordered by most recently updated. Non-admin users only see projects they own or are a member of. [Se...2 params

List projects in the current organization. Use this to find a project by name before acting on it, or to give the user an overview of their work. Returns up to `limit` projects ordered by most recently updated. Non-admin users only see projects they own or are a member of. [Se...

Parameters* required
limitinteger
Max projects to return (1–50). Default 20.default: 20
statusstring
Optional: only return projects with this status.one of PLANNING · ACTIVE · ON_HOLD · COMPLETED · CANCELLED
get_projectGet full detail on one project (team, milestones, task counts) by id. Use this after list_projects to resolve a name → id and pull enough context to reason about the project without a follow-up call. The caller can only see projects they own, are a member of, or have org-admin...1 params

Get full detail on one project (team, milestones, task counts) by id. Use this after list_projects to resolve a name → id and pull enough context to reason about the project without a follow-up call. The caller can only see projects they own, are a member of, or have org-admin...

Parameters* required
projectIdstring
Project id from list_projects.
list_tasksList tasks visible to the caller, with optional filters: projectId, status (TODO / IN_PROGRESS / REVIEW / DONE / BLOCKED), assigneeId, dueBefore / dueAfter (ISO dates), overdueOnly. Returns up to 50 tasks per call. For deeper drill-downs use get_task on a specific id. [Securit...7 params

List tasks visible to the caller, with optional filters: projectId, status (TODO / IN_PROGRESS / REVIEW / DONE / BLOCKED), assigneeId, dueBefore / dueAfter (ISO dates), overdueOnly. Returns up to 50 tasks per call. For deeper drill-downs use get_task on a specific id. [Securit...

Parameters* required
limitnumber
Default 25, max 50.
statusstring
one of TODO · IN_PROGRESS · REVIEW · DONE · BLOCKED
dueAfterstring
ISO date - show tasks due after this date.
dueBeforestring
ISO date - show tasks due before this date.
projectIdstring
Optional - restrict to one project.
assigneeIdstring
Optional - show tasks assigned to one user.
overdueOnlyboolean
When true, only return tasks past their due date and not DONE.
get_taskGet full detail on one task by id (subtasks, dependencies, recent comments). Caller must have visibility into the parent project. Out-of-scope task ids return not_found. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <...1 params

Get full detail on one task by id (subtasks, dependencies, recent comments). Caller must have visibility into the parent project. Out-of-scope task ids return not_found. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <...

Parameters* required
taskIdstring
Task id from list_tasks.
list_org_membersList active members of the caller's organization with name + role. For OWNER/ADMIN callers, also returns email and 2FA-enabled status. SCIM-deactivated members are excluded - they can't be assigned tasks until reactivated. Optional `role` filter (OWNER/ADMIN/MANAGER/MEMBER/GUE...2 params

List active members of the caller's organization with name + role. For OWNER/ADMIN callers, also returns email and 2FA-enabled status. SCIM-deactivated members are excluded - they can't be assigned tasks until reactivated. Optional `role` filter (OWNER/ADMIN/MANAGER/MEMBER/GUE...

Parameters* required
rolestring
one of OWNER · ADMIN · MANAGER · MEMBER · GUEST
limitnumber
Default 50, max 200.
list_risksList project risks visible to the caller. Filters: projectId (optional), severity (LOW/MEDIUM/HIGH/CRITICAL), category (SCHEDULE/RESOURCE/BUDGET/SCOPE), includeDismissed (default false). Returns up to 50 risks per call, ordered by severity descending then most-recent first. [S...5 params

List project risks visible to the caller. Filters: projectId (optional), severity (LOW/MEDIUM/HIGH/CRITICAL), category (SCHEDULE/RESOURCE/BUDGET/SCOPE), includeDismissed (default false). Returns up to 50 risks per call, ordered by severity descending then most-recent first. [S...

Parameters* required
limitnumber
Default 25, max 50.
categorystring
one of SCHEDULE · RESOURCE · BUDGET · SCOPE
severitystring
one of LOW · MEDIUM · HIGH · CRITICAL
projectIdstring
Optional - restrict to one project.
includeDismissedboolean
Default false.
create_projectCreate a new project in the current organization. The caller becomes the project owner. Returns the created project id - pass it to create_task to populate the project with work. Use list_projects first to confirm a similarly-named project does not already exist. [Security not...9 params

Create a new project in the current organization. The caller becomes the project owner. Returns the created project id - pass it to create_task to populate the project with work. Use list_projects first to confirm a similarly-named project does not already exist. [Security not...

Parameters* required
namestring
Project name, 2–255 chars.
typestring
STRATEGIC or OPERATIONAL.one of STRATEGIC · OPERATIONAL
colorstring
Optional hex color for UI display.
budgetnumber
Optional numeric budget in the project currency.
statusstring
Default PLANNING.one of PLANNING · ACTIVE · ON_HOLD · COMPLETED · CANCELLED
endDatestring
ISO 8601 end date (required, must be after startDate).
currencystring
ISO 4217 currency code, 3 letters. Default USD.
startDatestring
ISO 8601 start date (required).
descriptionstring
Optional description, up to 10000 chars.
create_taskCreate a task in an existing project. Use `list_projects` first if you only know the project by name. `projectId` and `title` are required; everything else is optional. For multi-step plans, prefer creating the parent task first, then subtasks with `parentId` set to its id. [S...15 params

Create a task in an existing project. Use `list_projects` first if you only know the project by name. `projectId` and `title` are required; everything else is optional. For multi-step plans, prefer creating the parent task first, then subtasks with `parentId` set to its id. [S...

Parameters* required
titlestring
Task title, 1–500 chars. Required.
epicIdstring
Optional epic grouping.
statusstring
Default TODO.one of TODO · IN_PROGRESS · REVIEW · DONE · BLOCKED
dueDatestring
ISO date the work must finish.
parentIdstring
Parent task id for subtasks.
prioritystring
Default MEDIUM.one of LOW · MEDIUM · HIGH · CRITICAL
progressnumber
0–100; default 0.
sprintIdstring
Optional sprint to scope the task to.
projectIdstring
Project id to create the task in. Required.
startDatestring
ISO date the work can start.
assigneeIdstring
User id to assign. Must be a member of the org.
descriptionstring
Optional description, up to 10000 chars.
isMilestoneboolean
Mark as a milestone (shown as a diamond on Gantt).
assigneeNamestring
Alternative to assigneeId - full name, first name, or email of an org member. Resolved fuzzy; ignored when assigneeId is also set.
estimatedHoursnumber
Estimated hours of effort.
update_taskPartially update one task. Pass only the fields you want to change: status (TODO/IN_PROGRESS/REVIEW/DONE/BLOCKED), priority (LOW/MEDIUM/HIGH/CRITICAL), dueDate (ISO or null to clear), startDate (ISO or null), assigneeId (user id or null to unassign), progress (0-100). Caller m...7 params

Partially update one task. Pass only the fields you want to change: status (TODO/IN_PROGRESS/REVIEW/DONE/BLOCKED), priority (LOW/MEDIUM/HIGH/CRITICAL), dueDate (ISO or null to clear), startDate (ISO or null), assigneeId (user id or null to unassign), progress (0-100). Caller m...

Parameters* required
statusstring
one of TODO · IN_PROGRESS · REVIEW · DONE · BLOCKED
taskIdstring
Task to update.
dueDatestring
ISO date or null to clear.
prioritystring
one of LOW · MEDIUM · HIGH · CRITICAL
progressnumber
Integer 0-100.
startDatestring
ISO date or null to clear.
assigneeIdstring
User id or null to unassign.
assign_taskAssign or unassign one task. Pass assigneeId=null to unassign. Caller must have task.assign on the project. Target must be an active member of the organization. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <onplana_u...2 params

Assign or unassign one task. Pass assigneeId=null to unassign. Caller must have task.assign on the project. Target must be an active member of the organization. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <onplana_u...

Parameters* required
taskIdstring
Task to (un)assign.
assigneeIdstring
User id or null to unassign.
move_task_to_sprintMove one task into a sprint (sprintId=null returns it to the backlog). Sprint must belong to the same project as the task. Caller must have sprint.manage on the project. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <...2 params

Move one task into a sprint (sprintId=null returns it to the backlog). Sprint must belong to the same project as the task. Caller must have sprint.manage on the project. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <...

Parameters* required
taskIdstring
Task to move.
sprintIdstring
Target sprint id, or null for backlog.
update_projectPartially update one project: name, description, status (PLANNING/ACTIVE/ON_HOLD/COMPLETED/CANCELLED), startDate, endDate, progress (0-100), budget (number or null), color. Only supplied fields change. Caller must have project.edit on the project. [Security note] Free-text fie...9 params

Partially update one project: name, description, status (PLANNING/ACTIVE/ON_HOLD/COMPLETED/CANCELLED), startDate, endDate, progress (0-100), budget (number or null), color. Only supplied fields change. Caller must have project.edit on the project. [Security note] Free-text fie...

Parameters* required
namestring
2-255 chars.
colorstring
budgetnumber
statusstring
one of PLANNING · ACTIVE · ON_HOLD · COMPLETED · CANCELLED
endDatestring
ISO date - must be after startDate when both set.
progressnumber
Integer 0-100.
projectIdstring
startDatestring
ISO date.
descriptionstring
add_project_memberAdd an EXISTING active org member to a project. Pass userId (look up with list_org_members first) and role (OWNER/MANAGER/MEMBER/CONTRIBUTOR/VIEWER). Caller must have project.members.manage on the project. For inviting a brand-new email outside the org, use the invitation UI -...3 params

Add an EXISTING active org member to a project. Pass userId (look up with list_org_members first) and role (OWNER/MANAGER/MEMBER/CONTRIBUTOR/VIEWER). Caller must have project.members.manage on the project. For inviting a brand-new email outside the org, use the invitation UI -...

Parameters* required
rolestring
one of OWNER · MANAGER · MEMBER · CONTRIBUTOR · VIEWER
userIdstring
Target user id (use list_org_members to look up).
projectIdstring
create_milestoneCreate a milestone on one project (zero-duration marker for key dates). Caller must have milestone.create on the project. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <onplana_user_content>...</onplana_user_content>...3 params

Create a milestone on one project (zero-duration marker for key dates). Caller must have milestone.create on the project. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped in <onplana_user_content>...</onplana_user_content>...

Parameters* required
titlestring
2-200 chars.
dueDatestring
ISO date.
projectIdstring
create_commentPost a comment on a task OR a project (exactly one parent). Useful for AI-generated status updates, follow-ups, or notes. Caller must have visibility into the parent project. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped...3 params

Post a comment on a task OR a project (exactly one parent). Useful for AI-generated status updates, follow-ups, or notes. Caller must have visibility into the parent project. [Security note] Free-text fields in this tool's results that originate from end-user input are wrapped...

Parameters* required
taskIdstring
Mutually exclusive with projectId.
contentstring
1-5000 chars.
projectIdstring
Mutually exclusive with taskId.
bulk_update_tasksApply the same partial update to many tasks at once. Pass taskIds (max 50) and any combination of: status (TODO/IN_PROGRESS/REVIEW/DONE/BLOCKED), priority (LOW/MEDIUM/HIGH/CRITICAL), shiftDueDateDays (positive or negative integer to add to each task's dueDate). Per-task failur...4 params

Apply the same partial update to many tasks at once. Pass taskIds (max 50) and any combination of: status (TODO/IN_PROGRESS/REVIEW/DONE/BLOCKED), priority (LOW/MEDIUM/HIGH/CRITICAL), shiftDueDateDays (positive or negative integer to add to each task's dueDate). Per-task failur...

Parameters* required
statusstring
one of TODO · IN_PROGRESS · REVIEW · DONE · BLOCKED
taskIdsarray
Up to 50 task ids.
prioritystring
one of LOW · MEDIUM · HIGH · CRITICAL
shiftDueDateDaysnumber
Integer days to add to each task's dueDate. Negative = earlier.
create_sprint_with_tasksCreate a sprint on a project AND move existing tasks into it in one atomic call. Pass projectId, name, startDate, endDate (ISO), optional goal, and taskIds (existing tasks on the same project to assign - up to 50). Out-of-scope or missing tasks are skipped with reasons; the sp...6 params

Create a sprint on a project AND move existing tasks into it in one atomic call. Pass projectId, name, startDate, endDate (ISO), optional goal, and taskIds (existing tasks on the same project to assign - up to 50). Out-of-scope or missing tasks are skipped with reasons; the sp...

Parameters* required
goalstring
Optional sprint goal, up to 500 chars.
namestring
2-100 chars.
endDatestring
ISO date - must be after startDate.
taskIdsarray
Up to 50 task ids to move.
projectIdstring
startDatestring
ISO date.
analyze_project_risksRun AI risk analysis on one project - detected risks persist to the project risks table (visible via list_risks). Use this when the user asks "what could go wrong on Project X" or before a sprint planning meeting. Caller must have visibility into the project. [Security note] F...1 params

Run AI risk analysis on one project - detected risks persist to the project risks table (visible via list_risks). Use this when the user asks "what could go wrong on Project X" or before a sprint planning meeting. Caller must have visibility into the project. [Security note] F...

Parameters* required
projectIdstring
generate_status_reportGenerate a Markdown status report for one project (current state, task counts, top risks, recommendations). Returns the report inline; does NOT email it (user can copy or ask "email this to ..." for a separate explicit step). Caller must have visibility into the project. [Secu...1 params

Generate a Markdown status report for one project (current state, task counts, top risks, recommendations). Returns the report inline; does NOT email it (user can copy or ask "email this to ..." for a separate explicit step). Caller must have visibility into the project. [Secu...

Parameters* required
projectIdstring
find_similar_projectsFind projects in this org similar to a given description OR to an existing project. Pass either projectId (similar to this project) or description (free-form). Returns up to 5 matches with similarity scores. Useful for "have we done a project like this before?" - requires the...3 params

Find projects in this org similar to a given description OR to an existing project. Pass either projectId (similar to this project) or description (free-form). Returns up to 5 matches with similarity scores. Useful for "have we done a project like this before?" - requires the...

Parameters* required
limitnumber
Default 5, max 20.
projectIdstring
Mutually exclusive with description.
descriptionstring
Mutually exclusive with projectId.
summarize_projectGenerate an executive status summary for one project - covering what changed since `sinceDays` ago (default 7), top risks, current blockers, and recommended next steps. Returns structured fields the model can render. Caller must have visibility into the project. [Security note...2 params

Generate an executive status summary for one project - covering what changed since `sinceDays` ago (default 7), top risks, current blockers, and recommended next steps. Returns structured fields the model can render. Caller must have visibility into the project. [Security note...

Parameters* required
projectIdstring
sinceDaysnumber
Default 7, max 90.
search_org_knowledgeSemantic + lexical hybrid search across this org's indexed content: projects, tasks, risks, goals, comments, and wiki pages. Use this BEFORE listing or scanning when the user asks "find me…" / "what was the rationale for…" / "have we discussed…" — it's an O(1) lookup against t...3 params

Semantic + lexical hybrid search across this org's indexed content: projects, tasks, risks, goals, comments, and wiki pages. Use this BEFORE listing or scanning when the user asks "find me…" / "what was the rationale for…" / "have we discussed…" — it's an O(1) lookup against t...

Parameters* required
limitnumber
Max results (default 6, max 20).
querystring
Natural-language search query. 5–500 chars.
scopestring
Narrow to one entity type or search all (default).one of projects · tasks · risks · goals · comments · wiki
searchDiscovery tool for the Onplana org. Returns up to 10 candidate matches across projects, tasks, risks, comments, and wiki pages. Each result has an opaque `id` that can be passed to the `fetch` tool to retrieve full content. Use this BEFORE attempting any list scan — the hybrid...1 params

Discovery tool for the Onplana org. Returns up to 10 candidate matches across projects, tasks, risks, comments, and wiki pages. Each result has an opaque `id` that can be passed to the `fetch` tool to retrieve full content. Use this BEFORE attempting any list scan — the hybrid...

Parameters* required
querystring
Natural-language search query, 1–500 chars.
fetchRetrieve full content for one resource by id. The id MUST be one previously returned by the `search` tool — opaque strings of the form `<type>:<cuid>` (e.g. `project:abc123…`). Returns title, a single-string content blob (capped at 8 KB with a "more in app" trailer for longer...1 params

Retrieve full content for one resource by id. The id MUST be one previously returned by the `search` tool — opaque strings of the form `<type>:<cuid>` (e.g. `project:abc123…`). Returns title, a single-string content blob (capped at 8 KB with a "more in app" trailer for longer...

Parameters* required
idstring
Opaque id from a prior `search` result, of the form `<type>:<cuid>`.
list_my_tasksList tasks assigned to YOU (the calling user). Resolves "me" server-side — no need to pass an assignee id. Optional filters: status (TODO / IN_PROGRESS / REVIEW / DONE / BLOCKED), overdueOnly (only tasks past due date and not DONE). Default returns 25, max 50. Use list_tasks i...3 params

List tasks assigned to YOU (the calling user). Resolves "me" server-side — no need to pass an assignee id. Optional filters: status (TODO / IN_PROGRESS / REVIEW / DONE / BLOCKED), overdueOnly (only tasks past due date and not DONE). Default returns 25, max 50. Use list_tasks i...

Parameters* required
limitnumber
Default 25, max 50.
statusstring
one of TODO · IN_PROGRESS · REVIEW · DONE · BLOCKED
overdueOnlyboolean
Only return tasks past their due date and not yet DONE.
list_overdueList tasks that are past their due date and NOT yet DONE — across every project visible to the caller. Optional projectId filter to narrow to one project. Returns up to 25 tasks ordered by most-overdue first, with a `daysOverdue` field so the model can prioritise response. Use...2 params

List tasks that are past their due date and NOT yet DONE — across every project visible to the caller. Optional projectId filter to narrow to one project. Returns up to 25 tasks ordered by most-overdue first, with a `daysOverdue` field so the model can prioritise response. Use...

Parameters* required
limitnumber
Default 25, max 50.
projectIdstring
Optional — narrow to one project.
list_team_membersList members of a SPECIFIC project (NOT the whole organization — use list_org_members for that). Returns user id + name + role (OWNER / MANAGER / MEMBER / CONTRIBUTOR / VIEWER, plus any custom roles your org has defined). The project owner is always included as the first row w...1 params

List members of a SPECIFIC project (NOT the whole organization — use list_org_members for that). Returns user id + name + role (OWNER / MANAGER / MEMBER / CONTRIBUTOR / VIEWER, plus any custom roles your org has defined). The project owner is always included as the first row w...

Parameters* required
projectIdstring
Project to list members for.
link_dependencyCreate a dependency between two tasks. Type is one of FINISH_TO_START (default — successor starts when predecessor finishes), START_TO_START, FINISH_TO_FINISH, START_TO_FINISH. Lag is in integer days; negative values create lead time (successor starts before predecessor finish...4 params

Create a dependency between two tasks. Type is one of FINISH_TO_START (default — successor starts when predecessor finishes), START_TO_START, FINISH_TO_FINISH, START_TO_FINISH. Lag is in integer days; negative values create lead time (successor starts before predecessor finish...

Parameters* required
lagnumber
Integer days. Default 0. Negative for lead time.
typestring
Default FINISH_TO_START. Use FINISH_TO_FINISH for "wait for predecessor to wrap before declaring this done."one of FINISH_TO_START · START_TO_START · FINISH_TO_FINISH · START_TO_FINISH
successorIdstring
Task that depends on the predecessor.
predecessorIdstring
Task that must complete (or start, depending on type) first.
submit_timesheetLog hours against a task as a timesheet entry. Records under the calling user, on the specified task within the specified project. Hours: 0.25 (15 minutes) to 24 — fractional values OK. Date: YYYY-MM-DD or ISO 8601. The entry starts in DRAFT status; submission for approval is...5 params

Log hours against a task as a timesheet entry. Records under the calling user, on the specified task within the specified project. Hours: 0.25 (15 minutes) to 24 — fractional values OK. Date: YYYY-MM-DD or ISO 8601. The entry starts in DRAFT status; submission for approval is...

Parameters* required
datestring
YYYY-MM-DD or ISO 8601.
hoursnumber
Between 0.25 and 24, inclusive. Fractional values OK.
notesstring
Optional free-text note about what the work covered.
taskIdstring
Task to log time against.
projectIdstring
Project the task belongs to. Sanity-checked server-side against taskId.

Onplana MCP server

Open-source TypeScript Model Context Protocol building blocks, extracted from Onplana's production MCP deployment. Two packages:

  • onplana-mcp-server — server template. Streamable HTTP transport, Bearer auth, prompt-injection containment, pluggable dispatcher.
  • onplana-mcp-client — typed TypeScript client SDK for calling the public Onplana MCP endpoint at https://api.onplana.com/api/mcp/v1.

CI MIT License

What this is

The transport layer of an MCP server — Streamable HTTP wiring, stateless mode, scoped Bearer auth, prompt-injection containment — done well, separated from the platform-specific tool registry. Use the server template to build your own MCP server with security best practices baked in. Use the client SDK to drive Onplana's hosted MCP from your own code.

The patterns are extracted from Onplana's production deployment (public docs at onplana.com/mcp) — the same layer that handles real Claude Desktop, Cursor, ChatGPT custom connector, and in-house agent traffic against the Onplana platform.

Why open-source

The MCP transport is the same for everyone. Most early MCP servers get the security primitives wrong:

  • Prompt injection. Tools that return user-generated content (task titles, comment bodies, wiki text) put that content directly into the model's context. Without containment, a hostile actor can plant "ignore previous instructions" in their own data and the next agent that reads it follows along.
  • Stateless transport. Most SDK examples assume in-memory session state, which breaks horizontal scaling and complicates the auth model.
  • Plan-gate semantics. Surfacing tools the caller can't actually invoke wastes turns and confuses the model.

Onplana solved these in production over six months of MCP-server work. Publishing the patterns is high-leverage:

  1. Other MCP authors get a known-good template instead of reinventing.
  2. The repo is a pretraining-signal surface — public GitHub READMEs are heavily weighted in next-gen LLM training data, and a repo with patterns + clear documentation about MCP improves model recall of "what good MCP servers look like."
  3. The dispatcher interface is the seam where your business logic plugs in. The transport is generic; what matters about your MCP server is the tool registry. Open-sourcing the transport doesn't give away anything proprietary.

The dispatcher implementation, tool catalog, plan-gate logic, audit infrastructure, and the rest of Onplana's ~600 LOC closed-source dispatcher stay in the closed monorepo because they encode platform business logic. If you build your own MCP server using this template, you write your own dispatcher — that's the work that matters and the work that's specific to your platform.

Repository layout

onplana-mcp-server/
├── packages/
│   ├── server-template/        # onplana-mcp-server (npm)
│   │   ├── src/
│   │   │   ├── transport.ts    # Streamable HTTP wiring
│   │   │   ├── auth.ts         # Bearer auth pattern
│   │   │   ├── promptInjection.ts  # wrapUserContent + escape
│   │   │   ├── dispatcher.ts   # Pluggable Dispatcher interface
│   │   │   └── index.ts
│   │   ├── tests/              # promptInjection + auth + transport
│   │   └── README.md
│   └── client/                 # onplana-mcp-client (npm)
│       ├── src/
│       │   ├── client.ts       # OnplanaMcpClient class
│       │   ├── types.ts        # Public type surface
│       │   └── index.ts
│       ├── tests/              # client.test.ts (stub fetch)
│       └── README.md
├── examples/
│   └── in-memory/              # Runnable demo with 3 toy tools
└── .github/workflows/
    ├── ci.yml                  # tsc + vitest on PR
    └── publish.yml             # npm publish on tag v*

Quickstart

Build a server

Install:

npm install github:Onplana/onplana-mcp-server @modelcontextprotocol/sdk express

Wire an Express app:

import express from 'express'
import {
  createMcpPostHandler,
  createMcpMethodNotAllowedHandler,
  requireBearerAuth,
  type Dispatcher,
} from 'onplana-mcp-server'

const dispatcher: Dispatcher = {
  async listTools(ctx) { /* return your tool descriptors */ return [] },
  async callTool(name, input, ctx) { /* dispatch to your tools */ return { output: {} } },
}

const auth = async (token: string) => {
  // Validate against your token store. Return AuthContext or null.
  return { userId: 'u', scopes: ['MCP_AGENT'] }
}

const app = express()
app.use(express.json())
app.use('/api/mcp/v1',
  requireBearerAuth({ auth, requiredScope: 'MCP_AGENT' }),
)
app.post('/api/mcp/v1', createMcpPostHandler({ dispatcher }))
app.get('/api/mcp/v1', createMcpMethodNotAllowedHandler())
app.delete('/api/mcp/v1', createMcpMethodNotAllowedHandler())
app.listen(3000)

Full quickstart in packages/server-template/README.md; runnable demo in examples/in-memory/.

Drive Onplana from code

Install:

npm install github:Onplana/onplana-mcp-server

Use:

import { OnplanaMcpClient } from 'onplana-mcp-client'

const client = new OnplanaMcpClient({
  url:   'https://api.onplana.com/api/mcp/v1',
  token: process.env.ONPLANA_PAT!,
})

const projects = await client.listProjects({ status: 'ACTIVE' })

// The differentiator vs other PM-tool MCPs: hybrid semantic + lexical
// search across your org's indexed content (projects, tasks, risks,
// goals, comments, wiki pages).
const { matches } = await client.searchOrgKnowledge({
  query: 'rationale for the 3-week design phase',
  scope: 'all',
  limit: 5,
})

Full client docs in packages/client/README.md.

Production checklist

The template + SDK get you running. Add these on top:

  • Per-token rate limiting. 60–120 req/min per Bearer token; agentic loops are noisier than humans.
  • Tenant cost cap. If your tools call paid LLMs, gate dispatch on month-to-date spend. Onplana's deployment uses aiMonthlyCostCapUsd with WARN / BLOCK modes.
  • Audit logging. Every dispatch should write an audit row tagged with actorType: 'mcp_agent' so admins can see what AI agents did in their tenant separately from human activity.
  • Plan / scope curation. Don't expose every internal tool. Onplana exposes 21 of 26; the suppressed 5 either need an in-app preview UI, are too risky for unsupervised invocation, or produce oversized payloads.
  • PREVIEW mode for risky mutations. Default mutating tools to preview-only on free tiers. Onplana ships this — agents see "what it would do" before users explicitly upgrade and re-run.
  • Idempotency keys. Hash the canonicalised input + a session id; store as a unique constraint on your audit row. A model retrying the same logical action shouldn't double-create.

Each of those is platform-specific. The template gives you the seam where they plug in (Dispatcher.callTool); your dispatcher implements them however your platform encodes those concepts.

Compatibility

  • Node.js ≥ 20 (for the server template and CI matrix); ≥ 18 for the client (uses ambient fetch).
  • @modelcontextprotocol/sdk@^1.29.0
  • express@^4.18.0 or express@^5.0.0

Tested against:

  • Claude Desktop (Custom Connector)
  • Cursor (~/.cursor/mcp.json)
  • ChatGPT custom connectors (where MCP is enabled in your account)
  • Gemini CLI + Gemini Code Assist (~/.gemini/settings.json)
  • GitHub Copilot in VS Code (.vscode/mcp.json)
  • The official MCP Inspector

Install in Gemini CLI

The repo ships a gemini-extension.json manifest at the root, so Gemini CLI installs Onplana with one command:

export ONPLANA_PAT=pat_paste-your-token-here  # mint at app.onplana.com/integrations
gemini extensions install https://github.com/Onplana/onplana-mcp-server

Restart the gemini CLI (or reload your VS Code / JetBrains window if you're using Gemini Code Assist). The Onplana tools appear in /mcp and your GEMINI.md context picks up the usage hints shipped in this repo.

Contributing

Issues + PRs welcome. The repo is small by design — the goal is for the transport patterns to be obvious, well-tested, and stable. Major-version bumps are reserved for breaking changes to the exported Dispatcher / BearerAuth / handler factory shapes. Patches and minors are for prompt-injection containment refinements, new helper utilities, additional test coverage.

License

MIT — © 2026 Onplana

See also

  • onplana.com/mcp — public docs page for the production Onplana MCP deployment (full tool catalog, setup instructions, security model)
  • onplana.com — Onplana, the PM platform. Cloud-agnostic, AI-native, Microsoft Project Online alternative
  • Model Context Protocol specification — the MCP standard
  • Anthropic prompt-injection guidance — the security pattern this repo's wrap implements
Featured
CodeRabbit
CodeRabbit
AI writes the code. CodeRabbit catches the slop.
Try For Free →
Keep your Mac awake
Keep your Mac awake
Keep your Mac awake while Claude Code and 40+ AI agents run. Sleeps when they're idle.
One time payment $9 →
Context.devContext.dev
Context.dev
Integrate web data into your AI product. One API to scrape website & brand data.
Get API Key Now →
Make your agent a DeFi expert
Make your agent a DeFi expert
Agent, run crypto. Access onchain data & trade routes via 1inch.
Install now →
Make money from your Skills
Make money from your Skills
On Capafy, your Skill runs online 24/7 as an agent product, and you get paid every time someone uses it.
Start earning →
AppSignal
AppSignal
Monitor with ease. Code with confidence.
Start Free Trial →
Registryactive
TransportHTTP
AuthRequired
UpdatedMay 20, 2026
View on GitHub