{
  "markdown": "<div align=\"center\">\n<h1>P4 Plan MCP Server</h1>\n\n![Support](https://img.shields.io/badge/Support-Community-yellow.svg)\n![License](https://img.shields.io/badge/License-MIT-blue.svg)\n\n<p>\n  <strong>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.</strong>\n</p>\n\n<nav aria-label=\"Quick navigation\">\n  <p align=\"center\">\n    <a href=\"#architecture\">Architecture</a> ·\n    <a href=\"#prerequisites\">Prerequisites</a> ·\n    <a href=\"#quick-start-npx\">Quick Start</a> ·\n    <a href=\"#installation\">Install</a> ·\n    <a href=\"#client-configuration\">Client Configurations</a> ·\n    <a href=\"#available-tools-28-total\">Tools</a>\n  </p>\n  <p align=\"center\">\n    <a href=\"#skills--resources\">Skills</a> ·\n    <a href=\"#logging\">Logging</a> ·\n    <a href=\"#troubleshooting\">Troubleshoot</a> ·\n    <a href=\"#development\">Development</a> ·\n    <a href=\"#license\">License</a>\n  </p>\n</nav>\n</div>\n\n## Architecture\n\nThis service acts as a **stateless** protocol adapter between MCP clients (AI assistants) and the P4 Plan GraphQL API, using **stdio transport** (stdin/stdout).\n\n```\n┌─────────────────┐     stdio (stdin/stdout)    ┌─────────────────┐     GraphQL      ┌─────────────────┐\n│   AI Client     │  ────────────────────────▶  │  P4 Plan MCP    │  ──────────────▶ │ P4 Plan GraphQL │\n│(Claude, Copilot)│   Spawns as child process   │    Server       │    Port 4000     │      API        │\n│                 │   P4PLAN_API_AUTH_TOKEN     │   (stateless)   │  Bearer token    │                 │\n└─────────────────┘          env var            └─────────────────┘  forwarded       └─────────────────┘\n```\n\nThe 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.\n\n## Prerequisites\n\n| Requirement             | Version                  | Notes                                                                                  |\n|-------------------------|--------------------------|----------------------------------------------------------------------------------------|\n| **Node.js**             | \\>= 20 (24+ recommended) | The server targets ES2023. Check with `node -v`.                                       |\n| **npm**                 | \\>= 9                    | Comes with Node.js. Check with `npm -v`.                                               |\n| **P4 Plan API**         | \\>= 2026.1.002           | Required for all tool operations. Earlier versions are not supported.                  |\n\n> **Tip:** Use [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions, or skip the Node.js requirement entirely by using [Docker](#docker).\n\n## Quick Start (npx)\n\nThe fastest way to get started — **no installation required**. Just configure your MCP client to use `npx`:\n\n```bash\nnpx -y @perforce/p4plan-mcp\n```\n\n`npx` automatically downloads and runs the latest version of the server. Your MCP client (VS Code, Claude Desktop, etc.) handles this for you — just add the config below and start chatting.\n\n**VS Code** — add to `.vscode/mcp.json`:\n\n```json\n{\n    \"servers\": {\n        \"p4-plan\": {\n            \"type\": \"stdio\",\n            \"command\": \"npx\",\n            \"args\": [\"-y\", \"@perforce/p4plan-mcp\"],\n            \"env\": {\n                \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n                \"P4PLAN_API_URL\": \"http://localhost:4000\"\n            }\n        }\n    }\n}\n```\n\n**Claude Desktop** — add to your config:\n\n```json\n{\n  \"mcpServers\": {\n    \"p4-plan\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@perforce/p4plan-mcp\"],\n      \"env\": {\n        \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n        \"P4PLAN_API_URL\": \"http://localhost:4000\"\n      }\n    }\n  }\n}\n```\n\n> **Note:** The `-y` flag auto-confirms the npm install prompt so the server starts without user interaction.\n\nSee [Client Configuration](#client-configuration) for more options including Docker, secure token prompts, and local builds.\n\n## MCP Registry\n\nThis server is published to the official [MCP Registry](https://registry.modelcontextprotocol.io) as **`io.github.perforce/p4plan-mcp`**. Discover it via the registry API:\n\n```bash\ncurl 'https://registry.modelcontextprotocol.io/v0/servers?search=io.github.perforce/p4plan-mcp'\n```\n\nMCP clients that support registry discovery can install the server by name without needing to know the npm package identifier.\n\n## Installation\n\n<details><summary><b>Build from source</b></summary>\n\nFor development or when you want to run from a local clone:\n\n```bash\nnpm ci\nnpm run build\n\n# For using npx locally\nnpm link\n```\n\n</details>\n\n<details><summary><b>Run from Docker</b></summary>\n\nRun 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.\n\nThe image is published to Docker Hub at [`perforce/p4plan-mcp`](https://hub.docker.com/r/perforce/p4plan-mcp), built multi-arch (`linux/amd64` + `linux/arm64`) on every release, with SLSA provenance and SBOM attestations.\n\n**VS Code** (`.vscode/mcp.json`):\n\n```json\n{\n    \"servers\": {\n        \"p4-plan\": {\n            \"type\": \"stdio\",\n            \"command\": \"docker\",\n            \"args\": [\n                \"run\", \"-i\", \"--rm\",\n                \"-e\", \"P4PLAN_API_AUTH_TOKEN=YOUR_JWT_TOKEN\",\n                \"-e\", \"P4PLAN_API_URL=http://host.docker.internal:4000\",\n                \"perforce/p4plan-mcp:latest\"\n            ]\n        }\n    }\n}\n```\n\n**Claude Desktop:**\n\n```json\n{\n  \"mcpServers\": {\n    \"p4-plan\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\", \"-i\", \"--rm\",\n        \"-e\", \"P4PLAN_API_AUTH_TOKEN=YOUR_JWT_TOKEN\",\n        \"-e\", \"P4PLAN_API_URL=http://host.docker.internal:4000\",\n        \"perforce/p4plan-mcp:latest\"\n      ]\n    }\n  }\n}\n```\n\n> **Note:** Use `host.docker.internal` (macOS/Windows) or `172.17.0.1` (Linux) to reach the P4 Plan GraphQL API running on the host machine.\n\n> **Pin a specific version** by replacing `:latest` with `:2026.2.0` (or whichever tag) for reproducible deployments.\n\n**Build locally** (for development against unreleased changes):\n\n```bash\ndocker build -t p4plan-mcp:dev .\n# then swap \"perforce/p4plan-mcp:latest\" for \"p4plan-mcp:dev\" in the configs above\n```\n\n</details>\n\n## Configuration\n\nCopy the example config and configure:\n\n```bash\ncp config-example.env .env\n```\n\nEdit `.env` with your settings:\n\n```dotenv\n# JWT token for authenticating with P4 Plan GraphQL API\nP4PLAN_API_AUTH_TOKEN=your-jwt-token\n\n# P4 Plan GraphQL API URL\nP4PLAN_API_URL=http://localhost:4000\n\n# Logging level\nLOG_LEVEL=debug\n\n# Search results limit (default: 400)\n# SEARCH_LIMIT=400\n\n# Allow self-signed TLS certificates (for HTTPS APIs with untrusted certs)\n# P4PLAN_ALLOW_SELF_SIGNED_CERTS=true\n```\n\n\nThe 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.\n\n## Authentication\n\nThe 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.\n\n### Obtaining a JWT Token\n\nGet a JWT token from the P4 Plan GraphQL API using `curl`. You can authenticate with either your **password** or a **Personal Access Token (PAT)**:\n\n<details><summary><b>Using your password</b></summary>\n\n```bash\ncurl -s -X POST http://localhost:4000/graphql \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"query\": \"mutation Login($loginUserInput: LoginUserInput!) { login(loginUserInput: $loginUserInput) { access_token } }\",\n    \"variables\": { \"loginUserInput\": { \"username\": \"YOUR_USERNAME\", \"password\": \"YOUR_PASSWORD\" } }\n  }'\n```\n\n</details>\n\n<details><summary><b>Using a Personal Access Token (recommended)</b></summary>\n\nA PAT can be used in place of your password in the same login mutation. This avoids exposing your actual password:\n\n```bash\ncurl -s -X POST http://localhost:4000/graphql \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"query\": \"mutation Login($loginUserInput: LoginUserInput!) { login(loginUserInput: $loginUserInput) { access_token } }\",\n    \"variables\": { \"loginUserInput\": { \"username\": \"YOUR_USERNAME\", \"password\": \"YOUR_PERSONAL_ACCESS_TOKEN\" } }\n  }'\n```\n\n</details>\n\nBoth methods return the same response:\n\n```json\n{\n  \"data\": {\n    \"login\": {\n      \"access_token\": \"eyJhbGciOiJIUzI1NiIs...\"\n    }\n  }\n}\n```\n\nCopy the `access_token` value and use it in your MCP client configuration.\n\n<details><summary><b>Getting a Personal Access Token</b></summary>\n\n1. Log in to P4 Plan\n2. Go to **User Settings** → **Personal Access Tokens**\n3. Click **Generate New Token**\n4. Set an appropriate expiration date\n5. Copy the token — use it in the login mutation above to obtain a JWT\n\n</details>\n\n> **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 `curl` command above.\n\n## Available Tools (28 total)\n\n### Projects\n\n<details>\n  <summary><strong><code>list_projects</code></strong> - List all active projects the user is a member of</summary>\n\n- **Use cases**: Discover project IDs needed by other tools\n\n</details>\n\n<details>\n  <summary><strong><code>get_project</code></strong> - Get project configuration including archivedStatus, backlog ID, and QA ID</summary>\n\n- **Parameters**: `projectId`\n- **Use cases**: Retrieve section IDs (backlog, QA, planning) for other tools\n\n</details>\n\n### Tasks\n\n<details>\n  <summary><strong><code>get_my_tasks</code></strong> - Get tasks assigned to current user (todoList)</summary>\n\n- **Parameters**: `showCompleted`, `showOnlyNextFourWeeks`, `showHidden`, `showPipelineTasksThatCannotStart`\n- **Use cases**: View personal work queue across all projects\n\n</details>\n\n<details>\n  <summary><strong><code>get_tasks</code></strong> - Get detailed information for one or more items by ID (max 20)</summary>\n\n- **Parameters**: `taskIds` (array of strings, max 20)\n- **Use cases**: Full item details, link inspection, batch retrieval of multiple items\n\n</details>\n\n<details>\n  <summary><strong><code>search_tasks</code></strong> - Search for items in a project section using P4 Plan Find queries</summary>\n\n- **Parameters**: `findQuery`, `projectId`\n- Uses P4 Plan Find query syntax for all searches. Call `read_skill` with `skillName=\"search-queries\"` first to get exact column names, operators, and value formats. For simple name search use `Itemname:Text(\"text\")`. Supports filtering by status, assignee, severity, item type, dates, boolean conditions, and combinations with AND/OR/NOT.\n- Each project has three sections (Backlog, QA, Planning) with different IDs.\n- **Use cases**: Item discovery, filtering, reporting\n\n</details>\n\n<details>\n  <summary><strong><code>create_item</code></strong> - Create any item type</summary>\n\n- **Types**: `backlog_task`, `bug`, `scheduled_task`, `sprint`, `release`, `sprint_task`\n- **Parameters**: `type`, `name`, `projectId`, `parentItemId`, `previousItemId`, and type-specific fields\n- **Use cases**: Task creation, sprint creation, bug filing\n\n</details>\n\n<details>\n  <summary><strong><code>update_item</code></strong> - Update any item (auto-detects type)</summary>\n\n- **Types**: BacklogTask, Bug, ScheduledTask, Sprint, Release\n- **Parameters**: `itemId`, plus any updatable fields (name, status, assignedTo, points, etc.)\n- **Use cases**: Status updates, assignments, estimation, sprint configuration\n\n</details>\n\n### Sprint & Release Management\n\n<details>\n  <summary><strong><code>commit_to_sprint</code></strong> - Commit a backlog task or bug to a sprint</summary>\n\n- **Parameters**: `taskId`, `sprintId`\n- **Use cases**: Sprint planning, backlog commitment\n\n</details>\n\n<details>\n  <summary><strong><code>uncommit_from_sprint</code></strong> - Remove a task from a sprint (return to backlog)</summary>\n\n- **Parameters**: `taskId`\n- **Use cases**: Sprint scope adjustment\n\n</details>\n\n### Custom Fields & Workflows\n\n<details>\n  <summary><strong><code>get_custom_columns</code></strong> - Get custom column definitions available in a project</summary>\n\n- **Parameters**: `projectId`\n- **Use cases**: Discover custom fields before reading/writing values\n\n</details>\n\n<details>\n  <summary><strong><code>get_custom_fields</code></strong> - Get custom field values set on a task</summary>\n\n- **Parameters**: `taskId`, `onlySet`\n- **Use cases**: Read project-specific metadata\n\n</details>\n\n<details>\n  <summary><strong><code>set_custom_field</code></strong> - Set a custom field value on a task</summary>\n\n- **Parameters**: `taskId`, `columnId`, `value`\n- **Use cases**: Update project-specific metadata\n\n</details>\n\n<details>\n  <summary><strong><code>get_workflows</code></strong> - Get workflow definitions and status IDs for a project</summary>\n\n- **Parameters**: `projectId`\n- **Use cases**: Discover workflow statuses for status transitions\n\n</details>\n\n### Task Actions\n\n<details>\n  <summary><strong><code>complete_task</code></strong> - Mark a task as completed</summary>\n\n- **Parameters**: `taskId`\n- **Use cases**: Quick status update convenience method\n\n</details>\n\n<details>\n  <summary><strong><code>start_task</code></strong> - Mark a task as in progress</summary>\n\n- **Parameters**: `taskId`\n- **Use cases**: Quick status update convenience method\n\n</details>\n\n### Comments & Attachments\n\n<details>\n  <summary><strong><code>get_comments</code></strong> - Get all comments on a task</summary>\n\n- **Parameters**: `taskId`\n- **Use cases**: Read discussion history\n\n</details>\n\n<details>\n  <summary><strong><code>post_comment</code></strong> - Post a new comment on a task</summary>\n\n- **Parameters**: `taskId`, `text`\n- **Use cases**: Add discussion, acceptance criteria, notes\n\n</details>\n\n<details>\n  <summary><strong><code>update_comment</code></strong> - Edit an existing comment</summary>\n\n- **Parameters**: `taskId`, `commentId`, `text`\n- **Use cases**: Correct or update existing comments\n\n</details>\n\n<details>\n  <summary><strong><code>delete_comment</code></strong> - Delete a comment from a task</summary>\n\n- **Parameters**: `taskId`, `commentId`\n- **Use cases**: Remove outdated or incorrect comments\n\n</details>\n\n<details>\n  <summary><strong><code>get_attachments</code></strong> - Get all attachments on a task</summary>\n\n- **Parameters**: `taskId`\n- **Use cases**: List attached files, discover paths for download\n\n</details>\n\n<details>\n  <summary><strong><code>download_attachment</code></strong> - Download and return attachment file content</summary>\n\n- **Parameters**: `taskId`, `path`\n- Text files returned inline, images as base64\n- **Use cases**: Read attached documents, view screenshots\n\n</details>\n\n<details>\n  <summary><strong><code>delete_attachment</code></strong> - Delete an attachment from a task</summary>\n\n- **Parameters**: `taskId`, `path`\n- **Use cases**: Remove outdated attachments\n\n</details>\n\n<details>\n  <summary><strong><code>set_cover_image</code></strong> - Set or unset the cover image for a task</summary>\n\n- **Parameters**: `taskId`, `imagePath`\n- **Use cases**: Set visual identity for cards/items\n\n</details>\n\n### Links\n\n<details>\n  <summary><strong><code>link_items</code></strong> - Create internal or external links</summary>\n\n- **Parameters**: `fromItemId`, `toItemId` or `url`, `relation` (blocks, duplicates, relatedTo)\n- **Use cases**: Dependency tracking, cross-references, external URLs\n\n</details>\n\n<details>\n  <summary><strong><code>unlink_items</code></strong> - Remove an internal or external link</summary>\n\n- **Parameters**: `fromItemId`, `toItemId` or `url`\n- **Use cases**: Clean up outdated dependencies\n\n</details>\n\n### Users\n\n<details>\n  <summary><strong><code>get_current_user</code></strong> - Get current user information</summary>\n\n- **Use cases**: Identity verification, user context\n\n</details>\n\n<details>\n  <summary><strong><code>list_project_users</code></strong> - List users in a project</summary>\n\n- **Parameters**: `projectId`\n- **Use cases**: Find user IDs for assignments, sprint member management\n\n</details>\n\n### Skills\n\n<details>\n  <summary><strong><code>read_skill</code></strong> - Read a P4 Plan skill document at runtime</summary>\n\n- **Parameters**: `skillName`\n- Returns the full Markdown content of the requested skill document. The AI agent **must** call this with `skillName=\"search-queries\"` before composing any `findQuery` for `search_tasks`.\n- Available skills: `project-navigation`, `search-queries`, `task-management`, `planning`, `backlog-refinement`, `bug-tracking`, `custom-fields`, `gantt-scheduling`, `workflows`\n- **Use cases**: Learn correct query syntax, discover tool usage patterns, understand domain concepts\n\n</details>\n\n## Client Configuration\n\n<details>\n  <summary><strong>VS Code (Copilot) — via npx (recommended)</strong></summary>\n\nCreate `.vscode/mcp.json` in your workspace:\n\n```json\n{\n    \"servers\": {\n        \"p4-plan\": {\n            \"type\": \"stdio\",\n            \"command\": \"npx\",\n            \"args\": [\"-y\", \"@perforce/p4plan-mcp\"],\n            \"env\": {\n                \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n                \"P4PLAN_API_URL\": \"http://localhost:4000\"\n            }\n        }\n    }\n}\n```\n\n> **Note:** The `-y` flag auto-confirms the npm install prompt so the server starts without user interaction.\n\n</details>\n\n<details>\n  <summary><strong>VS Code (Copilot) — via node (local build)</strong></summary>\n\nIf running from a local clone instead of npm:\n\n```json\n{\n    \"servers\": {\n        \"p4-plan\": {\n            \"type\": \"stdio\",\n            \"command\": \"node\",\n            \"args\": [\"/path/to/MCP/dist/main.js\"],\n            \"env\": {\n                \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n                \"P4PLAN_API_URL\": \"http://localhost:4000\"\n            }\n        }\n    }\n}\n```\n\n</details>\n\n<details>\n  <summary><strong>VS Code — with secure token prompt</strong></summary>\n\nFor added security, you can use VS Code input prompts to avoid storing tokens in files:\n\n```json\n{\n    \"inputs\": [\n        {\n            \"type\": \"promptString\",\n            \"id\": \"p4-plan-jwt\",\n            \"description\": \"P4 Plan JWT Token\",\n            \"password\": true\n        }\n    ],\n    \"servers\": {\n        \"p4-plan\": {\n            \"type\": \"stdio\",\n            \"command\": \"npx\",\n            \"args\": [\"-y\", \"@perforce/p4plan-mcp\"],\n            \"env\": {\n                \"P4PLAN_API_AUTH_TOKEN\": \"${input:p4-plan-jwt}\",\n                \"P4PLAN_API_URL\": \"http://localhost:4000\"\n            }\n        }\n    }\n}\n```\n\n</details>\n\n<details>\n  <summary><strong>Claude Desktop</strong></summary>\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"p4-plan\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@perforce/p4plan-mcp\"],\n      \"env\": {\n        \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n        \"P4PLAN_API_URL\": \"http://localhost:4000\"\n      }\n    }\n  }\n}\n```\n\nReplace `YOUR_JWT_TOKEN` with a token obtained from the login mutation (see [Obtaining a JWT Token](#obtaining-a-jwt-token)).\n\n</details>\n\n<details>\n  <summary><strong>Claude Code (CLI / VS Code extension)</strong></summary>\n\nCreate `.mcp.json` in your project root:\n\n```json\n{\n  \"mcpServers\": {\n    \"p4-plan\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@perforce/p4plan-mcp\"],\n      \"env\": {\n        \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n        \"P4PLAN_API_URL\": \"http://localhost:4000\"\n      }\n    }\n  }\n}\n```\n\nFor a local build, replace `\"command\"` and `\"args\"` with:\n\n```json\n{\n  \"mcpServers\": {\n    \"p4-plan\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/MCP/dist/main.js\"],\n      \"env\": {\n        \"P4PLAN_API_AUTH_TOKEN\": \"YOUR_JWT_TOKEN\",\n        \"P4PLAN_API_URL\": \"http://localhost:4000\"\n      }\n    }\n  }\n}\n```\n\nOr add it via the CLI:\n\n```bash\nclaude mcp add p4-plan \\\n  -e P4PLAN_API_AUTH_TOKEN=YOUR_JWT_TOKEN \\\n  -e P4PLAN_API_URL=http://localhost:4000 \\\n  -- npx -y @perforce/p4plan-mcp\n```\n\n> **Note:** The server name must come **before** the `-e` flags, otherwise the variadic `-e` parser consumes the name as an env value.\n\n**Verify it's running:** type `/mcp` inside Claude Code to check server status.\n\n> **Tip:** Place `.mcp.json` in your project root to share the config with your team (tokens excluded). For personal config, add the server to `~/.claude.json` instead.\n\n</details>\n\n### Verifying the Connection\n\n1. Ensure the P4 Plan GraphQL API is running\n2. Open VS Code with the workspace containing `.vscode/mcp.json`\n3. Look for \"MCP SERVERS\" in the Extensions sidebar — you should see \"p4-plan\" listed\n4. Start a new Copilot chat and ask \"What tasks are assigned to me?\"\n\n### Environment Variables\n\n- `P4PLAN_API_AUTH_TOKEN` - JWT token for authenticating with the P4 Plan GraphQL API\n- `P4PLAN_API_URL` - P4 Plan GraphQL API URL (default: `http://localhost:4000`)\n- `P4PLAN_ALLOW_SELF_SIGNED_CERTS` - Set to `true` to accept self-signed or untrusted TLS certificates when connecting to the API over HTTPS (default: `false`)\n- `LOG_LEVEL` - Logging level: `debug`, `info`, `warn`, `error` (default: `debug`)\n- `SEARCH_LIMIT` - Maximum number of results returned by `search_tasks` (default: `400`)\n\n## Skills & Resources\n\nThe server includes **skill files** — domain-specific guides that help AI agents construct correct tool calls. Skills are accessible in two ways:\n\n- **`read_skill` tool** — any MCP client can call `read_skill` with a `skillName` to fetch skill content at runtime. This is the primary access method and works with all clients.\n- **MCP resources** — skills are also registered as MCP resources (e.g., `skill://p4-plan/search-queries`) for clients that support native resource reading.\n\n| Skill              | Purpose                                                     |\n|--------------------|-------------------------------------------------------------|\n| project-navigation | Finding projects, items, and getting started                |\n| search-queries     | P4 Plan Find query syntax (column names, values, operators) |\n| task-management    | Task CRUD, status, assignments, comments, attachments       |\n| planning           | Sprints, releases, commitment, allocations                  |\n| backlog-refinement | Backlog items, estimation, prioritization                   |\n| bug-tracking       | Bugs, severity, QA section                                  |\n| custom-fields      | Custom columns, project-specific metadata                   |\n| gantt-scheduling   | Scheduled tasks, timeline, dependencies                     |\n| workflows          | Workflows, pipelines, status state machines                 |\n\nSee [`skills/README.md`](skills/README.md) for details on using skills with different AI clients.\n\n## Development\n\n<details><summary><b>Local Testing with npm link</b></summary>\n\nTo test the `npx` experience locally without publishing to npm:\n\n```bash\n# Build and create a global symlink\nnpm run build\nnpm link\n\n# Now test exactly as an end user would\nP4PLAN_API_AUTH_TOKEN=your-jwt-token npx @perforce/p4plan-mcp\n\n# Clean up when done\nnpm unlink -g @perforce/p4plan-mcp\n```\n\nThe symlink persists across rebuilds — just run `npm run build` after code changes.\n\n</details>\n\n<details><summary><b>Adding New Tools</b></summary>\n\n1. Create or edit a tools file in `src/tools/`\n2. Define the tool with:\n   - `name`: Unique tool identifier\n   - `description`: What the tool does (shown to AI)\n   - `inputSchema`: JSON Schema for parameters\n   - `handler`: Function that executes the tool\n\n3. Register in `ToolsModule`\n\n</details>\n\n<details><summary><b>Testing</b></summary>\n\n```bash\n# Unit tests\nnpm run test\n\n# E2E tests (MCP protocol compliance via @modelcontextprotocol/sdk)\nnpm run test:e2e\n```\n\n</details>\n\n### Logging\n\nThe server uses Winston with two transports:\n\n- **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 `warn` and `error` level messages are shown to keep the output clean.\n- **File:** Full debug logs are written to `logs/P4PlanMCP_<timestamp>.log`. Use these for detailed troubleshooting.\n\n> **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.\n\n## Protocol\n\nThis 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.\n\n- **Transport:** stdio (stdin/stdout)\n- **Protocol:** JSON-RPC 2.0\n- **Authentication:** `P4PLAN_API_AUTH_TOKEN` environment variable (validated at startup)\n- **SDK:** `@modelcontextprotocol/sdk` with `StdioServerTransport`\n\n## Troubleshooting\n\n<details>\n  <summary><strong>Server fails to start</strong></summary>\n\n1. **Check P4PLAN_API_AUTH_TOKEN is set:**\n   The server requires a valid JWT token in the `P4PLAN_API_AUTH_TOKEN` environment variable. If missing, it exits immediately with an error.\n\n2. **Check token is valid:**\n   If the token is expired or invalid, the server exits with \"Authentication failed\". Generate a new JWT using the login mutation.\n\n3. **Check GraphQL API is reachable:**\n   The P4 Plan GraphQL API must be accessible at the configured `P4PLAN_API_URL` (default: `http://localhost:4000`).\n\n</details>\n\n<details>\n  <summary><strong>Server not detected in VS Code</strong></summary>\n\n1. **Verify mcp.json syntax:**\n   Ensure your `.vscode/mcp.json` is valid JSON. Check for trailing commas.\n\n2. **Check the command is available:**\n   If using `npx`, ensure Node.js is in VS Code's PATH. If `npx` is not found, use the absolute path to `node` instead (see [local build config](#vs-code-copilot--via-node-local-build)).\n\n3. **Reload VS Code window:**\n   Press `Cmd+Shift+P` → \"Developer: Reload Window\"\n\n4. **Start a new chat:**\n   MCP servers are connected when a new chat session starts.\n\n</details>\n\n<details>\n  <summary><strong>Tools don't work</strong></summary>\n\n1. **Check GraphQL server is running:**\n   The P4 Plan GraphQL API must be accessible at the configured URL.\n\n2. **Check server logs:**\n   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.\n\n3. **Verify the JWT hasn't expired:**\n   Generate a new JWT if needed and update your mcp.json config.\n\n</details>\n\n## License\n\nThis project is licensed under the MIT License. See [LICENSE](LICENSE.txt) for details.\n",
  "bytes": 26779,
  "sha": "f074ca448d5982e3db67391295072fdaee82ceea955ffd695ff9498c40f5949b",
  "repo_slug": "perforce/p4plan-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_perforce_p4plan_mcp_af318aeb/readme"
}