MCP (Model Context Protocol) server for P4 Plan, enabling AI assistants like Claude and VS Code Copilot to interact with P4 Plan project management data.
Architecture · Prerequisites · Quick Start · Install · Client Configurations · Tools
Skills · Logging · Troubleshoot · Development · License
This service acts as a stateless protocol adapter between MCP clients (AI assistants) and the P4 Plan GraphQL API, using stdio transport (stdin/stdout).
┌─────────────────┐ stdio (stdin/stdout) ┌─────────────────┐ GraphQL ┌─────────────────┐
│ AI Client │ ────────────────────────▶ │ P4 Plan MCP │ ──────────────▶ │ P4 Plan GraphQL │
│(Claude, Copilot)│ Spawns as child process │ Server │ Port 4000 │ API │
│ │ P4PLAN_API_AUTH_TOKEN │ (stateless) │ Bearer token │ │
└─────────────────┘ env var └─────────────────┘ forwarded └─────────────────┘
The client spawns the MCP server as a child process. Authentication is provided via the P4PLAN_API_AUTH_TOKEN environment variable, which the server validates at startup and forwards to the GraphQL API on every tool call.
| Requirement | Version | Notes |
|---|---|---|
| Node.js | >= 20 (24+ recommended) | The server targets ES2023. Check with node -v. |
| npm | >= 9 | Comes with Node.js. Check with npm -v. |
| P4 Plan API | >= 2026.1.002 | Required for all tool operations. Earlier versions are not supported. |
Tip: Use nvm to manage Node.js versions, or skip the Node.js requirement entirely by using Docker.
Build from source
For development or when the package is not published to npm:
npm ci
npm run build
# For using npx locally
npm linkRun from Docker
Run the MCP server via Docker instead of installing Node.js locally. The MCP client (VS Code, Claude Desktop) spawns the container as a child process — same as npx, just using docker as the command.
Build the image:
docker build -t p4-plan-mcp .VS Code (.vscode/mcp.json):
{
"servers": {
"p4-plan": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "P4PLAN_API_AUTH_TOKEN=YOUR_JWT_TOKEN",
"-e", "P4PLAN_API_URL=http://host.docker.internal:4000",
"p4-plan-mcp"
]
}
}
}Claude Desktop:
{
"mcpServers": {
"p4-plan": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "P4PLAN_API_AUTH_TOKEN=YOUR_JWT_TOKEN",
"-e", "P4PLAN_API_URL=http://host.docker.internal:4000",
"p4-plan-mcp"
]
}
}
}Note: Use
host.docker.internal(macOS/Windows) or172.17.0.1(Linux) to reach the P4 Plan GraphQL API running on the host machine.
Copy the example config and configure:
cp config-example.env .envEdit .env with your settings:
# JWT token for authenticating with P4 Plan GraphQL API
P4PLAN_API_AUTH_TOKEN=your-jwt-token
# P4 Plan GraphQL API URL
P4PLAN_API_URL=http://localhost:4000
# Logging level
LOG_LEVEL=debug
# Search results limit (default: 400)
# SEARCH_LIMIT=400
# Allow self-signed TLS certificates (for HTTPS APIs with untrusted certs)
# P4PLAN_ALLOW_SELF_SIGNED_CERTS=true# Run the server (stdio mode — used by MCP clients)
npm start
# Or using npx (if published, or linked)
npx p4-plan-mcpThe server communicates via stdin/stdout. It is not meant to be run interactively — MCP clients (VS Code, Claude Desktop) spawn it as a child process automatically.
The MCP server requires a JWT token provided via the P4PLAN_API_AUTH_TOKEN environment variable. The token is validated at startup and forwarded to the P4 Plan GraphQL API on every tool call. No sessions or state are maintained.
Get a JWT token from the P4 Plan GraphQL API using curl. You can authenticate with either your password or a Personal Access Token (PAT):
Using your password
curl -s -X POST http://localhost:4000/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "mutation Login($loginUserInput: LoginUserInput!) { login(loginUserInput: $loginUserInput) { access_token } }",
"variables": { "loginUserInput": { "username": "YOUR_USERNAME", "password": "YOUR_PASSWORD" } }
}'Using a Personal Access Token (recommended)
A PAT can be used in place of your password in the same login mutation. This avoids exposing your actual password:
curl -s -X POST http://localhost:4000/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "mutation Login($loginUserInput: LoginUserInput!) { login(loginUserInput: $loginUserInput) { access_token } }",
"variables": { "loginUserInput": { "username": "YOUR_USERNAME", "password": "YOUR_PERSONAL_ACCESS_TOKEN" } }
}'Both methods return the same response:
{
"data": {
"login": {
"access_token": "eyJhbGciOiJIUzI1NiIs..."
}
}
}Copy the access_token value and use it in your MCP client configuration.
Getting a Personal Access Token
- Log in to P4 Plan
- Go to User Settings → Personal Access Tokens
- Click Generate New Token
- Set an appropriate expiration date
- Copy the token — use it in the login mutation above to obtain a JWT
Note: JWT tokens expire. When your token expires, the server will fail to start with an authentication error. Generate a new JWT using the same
curlcommand above.
list_projects - List all active projects the user is a member of
- Use cases: Discover project IDs needed by other tools
get_project - Get project configuration including archivedStatus, backlog ID, and QA ID
- Parameters:
projectId - Use cases: Retrieve section IDs (backlog, QA, planning) for other tools
get_my_tasks - Get tasks assigned to current user (todoList)
- Parameters:
showCompleted,showOnlyNextFourWeeks,showHidden,showPipelineTasksThatCannotStart - Use cases: View personal work queue across all projects
get_tasks - Get detailed information for one or more items by ID (max 20)
- Parameters:
taskIds(array of strings, max 20) - Use cases: Full item details, link inspection, batch retrieval of multiple items
search_tasks - Search for items in a project section using P4 Plan Find queries
- Parameters:
findQuery,projectId - Uses P4 Plan Find query syntax for all searches. Call
read_skillwithskillName="search-queries"first to get exact column names, operators, and value formats. For simple name search useItemname:Text("text"). Supports filtering by status, assignee, severity, item type, dates, boolean conditions, and combinations with AND/OR/NOT. - Each project has three sections (Backlog, QA, Planning) with different IDs.
- Use cases: Item discovery, filtering, reporting
create_item - Create any item type
- Types:
backlog_task,bug,scheduled_task,sprint,release,sprint_task - Parameters:
type,name,projectId,parentItemId,previousItemId, and type-specific fields - Use cases: Task creation, sprint creation, bug filing
update_item - Update any item (auto-detects type)
- Types: BacklogTask, Bug, ScheduledTask, Sprint, Release
- Parameters:
itemId, plus any updatable fields (name, status, assignedTo, points, etc.) - Use cases: Status updates, assignments, estimation, sprint configuration
commit_to_sprint - Commit a backlog task or bug to a sprint
- Parameters:
taskId,sprintId - Use cases: Sprint planning, backlog commitment
uncommit_from_sprint - Remove a task from a sprint (return to backlog)
- Parameters:
taskId - Use cases: Sprint scope adjustment
get_custom_columns - Get custom column definitions available in a project
- Parameters:
projectId - Use cases: Discover custom fields before reading/writing values
get_custom_fields - Get custom field values set on a task
- Parameters:
taskId,onlySet - Use cases: Read project-specific metadata
set_custom_field - Set a custom field value on a task
- Parameters:
taskId,columnId,value - Use cases: Update project-specific metadata
get_workflows - Get workflow definitions and status IDs for a project
- Parameters:
projectId - Use cases: Discover workflow statuses for status transitions
complete_task - Mark a task as completed
- Parameters:
taskId - Use cases: Quick status update convenience method
start_task - Mark a task as in progress
- Parameters:
taskId - Use cases: Quick status update convenience method
get_comments - Get all comments on a task
- Parameters:
taskId - Use cases: Read discussion history
post_comment - Post a new comment on a task
- Parameters:
taskId,text - Use cases: Add discussion, acceptance criteria, notes
update_comment - Edit an existing comment
- Parameters:
taskId,commentId,text - Use cases: Correct or update existing comments
delete_comment - Delete a comment from a task
- Parameters:
taskId,commentId - Use cases: Remove outdated or incorrect comments
get_attachments - Get all attachments on a task
- Parameters:
taskId - Use cases: List attached files, discover paths for download
download_attachment - Download and return attachment file content
- Parameters:
taskId,path - Text files returned inline, images as base64
- Use cases: Read attached documents, view screenshots
delete_attachment - Delete an attachment from a task
- Parameters:
taskId,path - Use cases: Remove outdated attachments
set_cover_image - Set or unset the cover image for a task
- Parameters:
taskId,imagePath - Use cases: Set visual identity for cards/items
link_items - Create internal or external links
- Parameters:
fromItemId,toItemIdorurl,relation(blocks, duplicates, relatedTo) - Use cases: Dependency tracking, cross-references, external URLs
unlink_items - Remove an internal or external link
- Parameters:
fromItemId,toItemIdorurl - Use cases: Clean up outdated dependencies
get_current_user - Get current user information
- Use cases: Identity verification, user context
list_project_users - List users in a project
- Parameters:
projectId - Use cases: Find user IDs for assignments, sprint member management
read_skill - Read a P4 Plan skill document at runtime
- Parameters:
skillName - Returns the full Markdown content of the requested skill document. The AI agent must call this with
skillName="search-queries"before composing anyfindQueryforsearch_tasks. - Available skills:
project-navigation,search-queries,task-management,planning,backlog-refinement,bug-tracking,custom-fields,gantt-scheduling,workflows - Use cases: Learn correct query syntax, discover tool usage patterns, understand domain concepts
VS Code (Copilot) — via npx (recommended)
Create .vscode/mcp.json in your workspace:
{
"servers": {
"p4-plan": {
"type": "stdio",
"command": "npx",
"args": ["-y", "p4-plan-mcp"],
"env": {
"P4PLAN_API_AUTH_TOKEN": "YOUR_JWT_TOKEN",
"P4PLAN_API_URL": "http://localhost:4000"
}
}
}
}Note: The
-yflag auto-confirms the npm install prompt so the server starts without user interaction.
VS Code (Copilot) — via node (local build)
If running from a local clone instead of npm:
{
"servers": {
"p4-plan": {
"type": "stdio",
"command": "node",
"args": ["/path/to/MCP/dist/main.js"],
"env": {
"P4PLAN_API_AUTH_TOKEN": "YOUR_JWT_TOKEN",
"P4PLAN_API_URL": "http://localhost:4000"
}
}
}
}VS Code — with secure token prompt
For added security, you can use VS Code input prompts to avoid storing tokens in files:
{
"inputs": [
{
"type": "promptString",
"id": "p4-plan-jwt",
"description": "P4 Plan JWT Token",
"password": true
}
],
"servers": {
"p4-plan": {
"type": "stdio",
"command": "npx",
"args": ["-y", "p4-plan-mcp"],
"env": {
"P4PLAN_API_AUTH_TOKEN": "${input:p4-plan-jwt}",
"P4PLAN_API_URL": "http://localhost:4000"
}
}
}
}Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"p4-plan": {
"command": "npx",
"args": ["-y", "p4-plan-mcp"],
"env": {
"P4PLAN_API_AUTH_TOKEN": "YOUR_JWT_TOKEN",
"P4PLAN_API_URL": "http://localhost:4000"
}
}
}
}Replace YOUR_JWT_TOKEN with a token obtained from the login mutation (see Obtaining a JWT Token).
Claude Code (CLI / VS Code extension)
Create .mcp.json in your project root:
{
"mcpServers": {
"p4-plan": {
"command": "npx",
"args": ["-y", "p4-plan-mcp"],
"env": {
"P4PLAN_API_AUTH_TOKEN": "YOUR_JWT_TOKEN",
"P4PLAN_API_URL": "http://localhost:4000"
}
}
}
}For a local build, replace "command" and "args" with:
{
"mcpServers": {
"p4-plan": {
"command": "node",
"args": ["/path/to/MCP/dist/main.js"],
"env": {
"P4PLAN_API_AUTH_TOKEN": "YOUR_JWT_TOKEN",
"P4PLAN_API_URL": "http://localhost:4000"
}
}
}
}Or add it via the CLI:
claude mcp add p4-plan \
-e P4PLAN_API_AUTH_TOKEN=YOUR_JWT_TOKEN \
-e P4PLAN_API_URL=http://localhost:4000 \
-- npx -y p4-plan-mcpNote: The server name must come before the
-eflags, otherwise the variadic-eparser consumes the name as an env value.
Verify it's running: type /mcp inside Claude Code to check server status.
Tip: Place
.mcp.jsonin your project root to share the config with your team (tokens excluded). For personal config, add the server to~/.claude.jsoninstead.
- Ensure the P4 Plan GraphQL API is running
- Open VS Code with the workspace containing
.vscode/mcp.json - Look for "MCP SERVERS" in the Extensions sidebar — you should see "p4-plan" listed
- Start a new Copilot chat and ask "What tasks are assigned to me?"
P4PLAN_API_AUTH_TOKEN- JWT token for authenticating with the P4 Plan GraphQL APIP4PLAN_API_URL- P4 Plan GraphQL API URL (default:http://localhost:4000)P4PLAN_ALLOW_SELF_SIGNED_CERTS- Set totrueto accept self-signed or untrusted TLS certificates when connecting to the API over HTTPS (default:false)LOG_LEVEL- Logging level:debug,info,warn,error(default:debug)SEARCH_LIMIT- Maximum number of results returned bysearch_tasks(default:400)
The server includes skill files — domain-specific guides that help AI agents construct correct tool calls. Skills are accessible in two ways:
read_skilltool — any MCP client can callread_skillwith askillNameto fetch skill content at runtime. This is the primary access method and works with all clients.- MCP resources — skills are also registered as MCP resources (e.g.,
skill://p4-plan/search-queries) for clients that support native resource reading.
| Skill | Purpose |
|---|---|
| project-navigation | Finding projects, items, and getting started |
| search-queries | P4 Plan Find query syntax (column names, values, operators) |
| task-management | Task CRUD, status, assignments, comments, attachments |
| planning | Sprints, releases, commitment, allocations |
| backlog-refinement | Backlog items, estimation, prioritization |
| bug-tracking | Bugs, severity, QA section |
| custom-fields | Custom columns, project-specific metadata |
| gantt-scheduling | Scheduled tasks, timeline, dependencies |
| workflows | Workflows, pipelines, status state machines |
See skills/README.md for details on using skills with different AI clients.
Local Testing with npm link
To test the npx experience locally without publishing to npm:
# Build and create a global symlink
npm run build
npm link
# Now test exactly as an end user would
P4PLAN_API_AUTH_TOKEN=your-jwt-token npx p4-plan-mcp
# Clean up when done
npm unlink -g p4-plan-mcpThe symlink persists across rebuilds — just run npm run build after code changes.
Adding New Tools
-
Create or edit a tools file in
src/tools/ -
Define the tool with:
name: Unique tool identifierdescription: What the tool does (shown to AI)inputSchema: JSON Schema for parametershandler: Function that executes the tool
-
Register in
ToolsModule
Testing
# Unit tests
npm run test
# E2E tests (MCP protocol compliance via @modelcontextprotocol/sdk)
npm run test:e2ePublishing to npm
The package is configured for npm publishing with npx support:
# Manual publish
npm publish
# Or via GitHub Actions (auto-publishes on release tag)
git tag v1.0.0
git push origin v1.0.0
# → Create a GitHub Release → workflow publishes to npmThe server uses Winston with two transports:
- Console (stderr): Only warnings and errors are written to stderr. In VS Code, these appear in the Output panel under the "p4-plan" dropdown. Only
warnanderrorlevel messages are shown to keep the output clean. - File: Full debug logs are written to
logs/P4PlanMCP_<timestamp>.log. Use these for detailed troubleshooting.
Note: All console output goes to stderr (never stdout) because stdout is the MCP protocol channel. VS Code labels all stderr output as
[warning]— this is expected behavior and does not indicate a problem.
This server uses the MCP stdio transport — communication happens over stdin/stdout using JSON-RPC 2.0 messages. The client spawns the server as a child process.
- Transport: stdio (stdin/stdout)
- Protocol: JSON-RPC 2.0
- Authentication:
P4PLAN_API_AUTH_TOKENenvironment variable (validated at startup) - SDK:
@modelcontextprotocol/sdkwithStdioServerTransport
Server fails to start
-
Check P4PLAN_API_AUTH_TOKEN is set: The server requires a valid JWT token in the
P4PLAN_API_AUTH_TOKENenvironment variable. If missing, it exits immediately with an error. -
Check token is valid: If the token is expired or invalid, the server exits with "Authentication failed". Generate a new JWT using the login mutation.
-
Check GraphQL API is reachable: The P4 Plan GraphQL API must be accessible at the configured
P4PLAN_API_URL(default:http://localhost:4000).
Server not detected in VS Code
-
Verify mcp.json syntax: Ensure your
.vscode/mcp.jsonis valid JSON. Check for trailing commas. -
Check the command is available: If using
npx, ensure Node.js is in VS Code's PATH. Ifnpxis not found, use the absolute path tonodeinstead (see local build config). -
Reload VS Code window: Press
Cmd+Shift+P→ "Developer: Reload Window" -
Start a new chat: MCP servers are connected when a new chat session starts.
Tools don't work
-
Check GraphQL server is running: The P4 Plan GraphQL API must be accessible at the configured URL.
-
Check server logs: In VS Code, check the Output panel → select "p4-plan" from the dropdown to see warnings/errors. For full debug logs, check the
logs/directory. -
Verify the JWT hasn't expired: Generate a new JWT if needed and update your mcp.json config.
This project is licensed under the MIT License. See LICENSE for details.