About Polarion MCP
Polarion MCP is an MCP server published by phillipboesger in the AI category: mCP server for the Polarion ALM REST API, with an optional HTTP wrapper for Custom GPTs. Works with Claude, VS Code, GitHub Copilot.
The repository has 5 stars and 2 forks, with the last commit 2 days ago. Recent commit activity is the strongest signal that reported issues will get attention.
Install
git clone https://github.com/phillipboesger/polarion-mcpThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Polarion MCP
Powered by Claude · Grounded in docs
Security checks
Static checks derived from the repository 3 days ago. Heuristics on the source, not an audit.
- ✓README presentThe repository ships documentation.
- ✓License declaredUsable under a stated license.
- ✓Tests presentA test suite exists in the repository.
- ✓Dependencies pinnedA lockfile pins dependency versions.
- !No dynamic code executionSource scan found eval or shell execution. Review how tool inputs reach it before granting credentials.
1 check has not been run yet.
Releases
README
Polarion MCP
Connect Claude, VS Code Copilot, and ChatGPT directly to Polarion ALM.
An open-source Model Context Protocol server that exposes 284 Polarion REST operations as AI-native tools.
Product page · Docs · Docker image
Table of Contents
- Features
- Requirements
- Getting Started
- Available Tools
- Configuration
- Usage Examples
- Architecture
- Security
- Contributing
- Acknowledgements
- License
Features
- Strict Type Validation — Zod schemas validate all inputs with Polarion query grammar support
- Hardened Error Handling — Standardized MCP errors with automatic token sanitization
- Pagination Helpers — Built-in utilities for easy result navigation
- Security Checks — Validates required environment variables and never logs sensitive data
- Multiple Transports — HTTP (Streamable MCP) and stdio support
- CI/CD Ready — TypeScript checks and automated Docker publishing included
Requirements
- Node.js v20+
- Polarion Personal Access Token (PAT) with read permissions
Getting Started
Choose an auth method
Every method ends at a Polarion Personal Access Token (PAT). They differ in where that token lives and which clients can use them.
| Method | Token lives | Use it for |
|---|---|---|
| A. Local stdio + PAT | in the client's MCP config on your machine | Claude Code, Claude Desktop (local server), VS Code Copilot. One user, no server to run. |
| B. HTTP server + PAT header | sent by the client on every request | Claude Code, VS Code Copilot, curl, scripts. Clients that can set a static Authorization header. |
| C. HTTP server + OAuth login | pasted once on a login page, then held by the client, encrypted | Claude.ai, Claude Desktop and mobile, ChatGPT connectors (they cannot send custom headers). Also works for Claude Code and VS Code. |
| D. REST wrapper + API key | one shared PAT in the server's environment | ChatGPT Custom GPT Actions. Every caller acts as the same Polarion user. |
| E. Custom GPT + OAuth login | pasted once on a login page, then held by ChatGPT, encrypted | ChatGPT Custom GPT Actions, each user under their own Polarion account. |
B, C and E run the same server: MCP_PUBLIC_URL adds the login on top of B,
and GPT_CLIENT_ID/GPT_CLIENT_SECRET add the Custom GPT login on top of C,
so one deployment can serve all three.
Why two URLs?
API_BASE_URLis where Polarion's REST API lives, e.g.https://polarion.example.com/polarion/rest/v1(always ending in/polarion/rest/v1). The server calls it. Required by every method.MCP_PUBLIC_URLis this server's own public address as clients see it, e.g.https://mcp.example.com(origin only, no path). Only method C needs it. Behind a TLS proxy the process only seeshttp://127.0.0.1:3000, yet the OAuth metadata it publishes must contain absolute HTTPS URLs the client can reach (issuer,/authorize,/token,/register). The server does not guess this from the request'sHostheader, because a spoofed header would then change the issuer.
The client never needs API_BASE_URL. For B and C it only gets the connector
URL: the server's public origin plus /mcp.
Prerequisites
-
Polarion with the REST API enabled (
com.siemens.polarion.rest.enabled=trueinpolarion.properties). -
A Polarion PAT per user: Polarion, My Account > Personal Access Tokens. The token carries the user's own permissions.
-
Node.js 22+ or Docker. From source:
git clone https://github.com/phillipboesger/polarion-mcp.git cd polarion-mcp npm ci # also runs the build
A. Local stdio + PAT
The client starts the server as a subprocess; nothing listens on the network.
-
Build from source (see Prerequisites) or pull the image:
docker pull ghcr.io/phillipboesger/polarion-mcp:latest. -
Register it with your client:
Claude Code
claude mcp add polarion \ -e API_BASE_URL=https://polarion.example.com/polarion/rest/v1 \ -e BEARER_TOKEN=<your-polarion-pat> \ -- node /absolute/path/to/polarion-mcp/build/index.jsClaude Desktop (
claude_desktop_config.json, then restart the app){ "mcpServers": { "polarion": { "command": "node", "args": ["/absolute/path/to/polarion-mcp/build/index.js"], "env": { "API_BASE_URL": "https://polarion.example.com/polarion/rest/v1", "BEARER_TOKEN": "<your-polarion-pat>" } } } }VS Code Copilot (
.vscode/mcp.json; VS Code prompts for the token and stores it securely){ "inputs": [ { "type": "promptString", "id": "polarion-pat", "description": "Polarion PAT", "password": true } ], "servers": { "polarion": { "type": "stdio", "command": "node", "args": ["/absolute/path/to/polarion-mcp/build/index.js"], "env": { "API_BASE_URL": "https://polarion.example.com/polarion/rest/v1", "BEARER_TOKEN": "${input:polarion-pat}" } } } }With Docker instead of Node, replace the command in any of the above with:
docker run --rm -i \ -e API_BASE_URL=https://polarion.example.com/polarion/rest/v1 \ -e BEARER_TOKEN=<your-polarion-pat> \ ghcr.io/phillipboesger/polarion-mcp:latest \ node build/index.js -
Verify: in Claude Code run
/mcp(server shows connected), then ask "list my Polarion projects".
B. HTTP server + PAT header
One shared server that holds no credentials; each client sends its own PAT.
Server
-
Start it. The image runs the Streamable HTTP MCP server by default:
docker run -d --name polarion-mcp \ -e API_BASE_URL=https://polarion.example.com/polarion/rest/v1 \ -e MCP_ALLOWED_HOSTS=mcp.example.com \ -p 127.0.0.1:3000:3000 \ ghcr.io/phillipboesger/polarion-mcp:latestFrom source:
MCP_HTTP_HOST=127.0.0.1 API_BASE_URL=... npm run start:mcp-http. -
Put TLS in front of it (reverse proxy forwarding
/mcpto127.0.0.1:3000). The PAT travels in a header, so never expose the plaintext port. For a Polarion server's own Apache, see docs/deployment.md. -
Verify:
curl -s https://mcp.example.com/health curl -si -X POST https://mcp.example.com/mcp \ -H 'authorization: Bearer <your-polarion-pat>' \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}' \ | head -1 # HTTP/1.1 200
Clients
-
Claude Code
claude mcp add --transport http polarion https://mcp.example.com/mcp \ --header "Authorization: Bearer <your-polarion-pat>" -
VS Code Copilot (
.vscode/mcp.json){ "inputs": [ { "type": "promptString", "id": "polarion-pat", "description": "Polarion PAT", "password": true } ], "servers": { "polarion": { "type": "http", "url": "https://mcp.example.com/mcp", "headers": { "Authorization": "Bearer ${input:polarion-pat}" } } } } -
Your own code: see Usage Examples.
Claude.ai and Claude Desktop connectors cannot set a header; use C for them.
C. HTTP server + OAuth login
Same server as B plus MCP_PUBLIC_URL. A client connecting without a token
gets a 401 pointing at the login; the user pastes their PAT once, the server
checks it against Polarion and hands the client tokens that carry the PAT
encrypted under MCP_TOKEN_SECRET. The server stores nothing; only it can
read the tokens.
Server
-
Pick the public HTTPS hostname. It must be reachable from where the client connects: Claude.ai and Claude Desktop/mobile connectors connect from Anthropic's cloud, so the host must be reachable from the internet (a VPN- or intranet-only host will not work). Claude Code and VS Code connect from your own machine, so an internal host is fine for them.
-
Start it:
docker run -d --name polarion-mcp \ -e API_BASE_URL=https://polarion.example.com/polarion/rest/v1 \ -e MCP_PUBLIC_URL=https://mcp.example.com \ -e MCP_TOKEN_SECRET=$(openssl rand -base64 48) \ -e MCP_ALLOWED_HOSTS=mcp.example.com \ -p 127.0.0.1:3000:3000 \ ghcr.io/phillipboesger/polarion-mcp:latestThe log must show
OAuth login enabled at https://mcp.example.com/authorize. StoreMCP_TOKEN_SECRETlike a password and keep it fixed: it is what lets logins survive restarts and redeploys (and must be the same on every instance behind a load balancer). Changing it logs everyone out. -
Configure the TLS reverse proxy to forward all of these paths, or the login breaks mid-flow:
/mcp,/authorize,/token,/register,/polarion-login,/.well-known/oauth-authorization-server,/.well-known/oauth-protected-resource(prefix match), and for method E also/gpt/and/api/toolsplus/openapi-gpt.json. A dedicated hostname that forwards/entirely is simplest. The paths live at the root, so the server cannot sit under a sub-path such ashttps://host/polarion-mcp. Apache block for the Polarion host: docs/deployment.md. -
Verify:
# 401 with WWW-Authenticate: this is what makes a client offer the login curl -si -X POST https://mcp.example.com/mcp \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | grep -i www-authenticate curl -s https://mcp.example.com/.well-known/oauth-protected-resource/mcp curl -s https://mcp.example.com/.well-known/oauth-authorization-serverEvery URL in the two JSON documents must start with
https://mcp.example.com.
Clients
- Claude.ai (also syncs to Claude Desktop and mobile): Settings >
Connectors > Add custom connector, name it, URL
https://mcp.example.com/mcp, leave OAuth Client ID/Secret empty (the client registers itself). If Claude.ai offers a choice of OAuth client, pick automatic (dynamic) registration: this server does not support Claude's published client identity. Click Connect, paste your PAT on the page that opens, click Connect again. On Team/Enterprise plans an owner may have to add the connector for the organization first. - Claude Code:
claude mcp add --transport http polarion https://mcp.example.com/mcp, then run/mcp, selectpolarion, Authenticate; the login page opens in your browser. - ChatGPT (Plus/Pro/Business/Enterprise): Settings > Security and login,
turn on Developer mode (on Business/Enterprise an admin may have to allow
custom connectors first). Then add a custom connector / app with URL
https://mcp.example.com/mcpand authentication OAuth; leave client ID and secret empty, ChatGPT registers itself. Paste your PAT on the page that opens. - VS Code Copilot: add the server as in B but without
headers; VS Code asks you to authenticate on first use.
How long a login lasts: as long as Polarion accepts the PAT. The client
renews its access token silently every hour; each renewal re-checks the PAT
with Polarion, so revoking the PAT (or its expiry date passing) ends the
login at the next renewal and the user is asked to log in again. A server
restart does not log anyone out as long as MCP_TOKEN_SECRET stays the same.
There is no per-session logout: to cut off one user, revoke their PAT in
Polarion; to cut off everyone, change MCP_TOKEN_SECRET.
D. REST wrapper + API key (ChatGPT)
A plain REST surface for Custom GPT Actions, not MCP. It uses one PAT for all callers; there is no per-user login.
-
Start it:
docker run -d --name polarion-rest \ -e API_BASE_URL=https://polarion.example.com/polarion/rest/v1 \ -e BEARER_TOKEN=<service-account-pat> \ -e HTTP_API_KEY=$(openssl rand -hex 32) \ -p 127.0.0.1:3000:3000 \ ghcr.io/phillipboesger/polarion-mcp:latest \ node build/http-server.js -
Publish it over HTTPS (reverse proxy), then check
curl -s https://gpt.example.com/health. -
In the GPT editor: Configure > Actions > Create new action > Import from URL
https://gpt.example.com/openapi-gpt.json(30-tool subset that fits ChatGPT's limit). Authentication: API Key, Auth Type Bearer, paste theHTTP_API_KEYvalue.
E. Custom GPT + OAuth login
The Custom GPT Action logs every user in with their own PAT, like C. It runs on the C server; Actions cannot do the automatic client registration or PKCE that connectors use, so the GPT gets a fixed client id and secret and its own two endpoints.
Server
-
Set up C, including
MCP_TOKEN_SECRET. The host must be reachable from the internet (ChatGPT calls it from OpenAI's cloud). -
Add a client id and secret for the GPT and restart:
-e GPT_CLIENT_ID=polarion-gpt \ -e GPT_CLIENT_SECRET=$(openssl rand -hex 32)The log must show
Custom GPT OAuth enabled: authorize https://mcp.example.com/gpt/authorize, .... -
Forward
/gpt/,/api/toolsand/openapi-gpt.jsonin the reverse proxy too (see C step 3).
GPT editor
-
Configure > Actions > Create new action > Import from URL
https://mcp.example.com/openapi-gpt.json. -
Authentication > OAuth:
Field Value Client ID the GPT_CLIENT_IDvalueClient Secret the GPT_CLIENT_SECRETvalueAuthorization URL https://mcp.example.com/gpt/authorizeToken URL https://mcp.example.com/gpt/tokenScope polarionToken Exchange Method Default (POST request) or Basic authorization header; both work -
Save. The server only accepts ChatGPT's own callbacks (
https://chatgpt.com/aip/<gpt-id>/oauth/callback), so there is nothing to allowlist. -
Test: in the GPT preview ask "list my Polarion projects", click Sign in with mcp.example.com, paste your PAT. Later calls run silently until the PAT is revoked or expires.
Local development
npm ci
cp .env.example .env # set API_BASE_URL; BEARER_TOKEN only for stdio / REST mode
npm run build
npm run start:mcp-http # Streamable HTTP MCP server on :3000
See Usage Examples below for a Node.js client.
Available Tools
284 tools are generated from the Polarion OpenAPI spec. A few representative examples:
| Tool | Description |
|---|---|
getAllWorkItems |
List work items across a project |
getWorkItem |
Fetch a specific work item by ID |
getAllDocuments |
List documents in a project |
getDocument |
Get a specific document |
postWorkItems |
Create new work items |
patchWorkItem |
Update an existing work item |
The full list is generated from src/tools.ts via npm run generate-tools.
Configuration
Environment Variables
# Required
API_BASE_URL=https://your-polarion.com/polarion/rest/v1
# Required for stdio and REST (ChatGPT) mode only. The MCP HTTP server ignores it:
# each client sends its own PAT
BEARER_TOKEN=your_polarion_personal_access_token
# Optional
MCP_HTTP_PORT=3000 # port for MCP HTTP server (default 3000)
MCP_HTTP_HOST=127.0.0.1 # bind address (default 0.0.0.0); use loopback behind a TLS proxy
MCP_PUBLIC_URL=https://mcp.example.com # public HTTPS origin (no path); enables the OAuth login page
MCP_ALLOWED_HOSTS=your-host.com # DNS-rebinding protection (comma-separated)
MCP_TOKEN_SECRET=... # min. 32 chars; keeps OAuth logins valid across restarts (keep it fixed)
MCP_ALLOWED_REDIRECT_PREFIXES=https://claude.ai/api/mcp/auth_callback # OAuth callbacks clients may register (set it!)
TRUST_PROXY=loopback # behind a reverse proxy: rate limits per client, not per proxy
MCP_SESSION_IDLE_MINUTES=60 # close unused MCP sessions (clients re-initialize on their own)
MCP_MAX_SESSIONS=1000 # cap on concurrent sessions (least recently used is dropped)
MCP_TOOLS=getWorkItems,getWorkItem # tool allowlist; others are neither listed nor callable
MCP_READ_ONLY=true # only read-only tools
MCP_OMIT_OUTPUT_SCHEMA=true # shrinks tools/list from about 840 KB to 530 KB
GPT_CLIENT_ID=polarion-gpt # Custom GPT OAuth client (method E), with GPT_CLIENT_SECRET
GPT_CLIENT_SECRET=...
NODE_TLS_REJECT_UNAUTHORIZED=0 # disable SSL verification for self-signed certs
Usage Examples
Node.js client
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "my-client", version: "1.0.0" });
await client.connect(
new StreamableHTTPClientTransport(new URL("http://localhost:3000/mcp"), {
requestInit: { headers: { Authorization: "Bearer your_polarion_pat" } },
})
);
const result = await client.callTool({
name: "getAllWorkItems",
arguments: { projectId: "MYPROJECT", query: "status:open", pageSize: 10 },
});
Pagination
All list operations support pageSize and pageStartIndex parameters:
const page1 = await client.callTool({
name: "getAllWorkItems",
arguments: { projectId: "MYPROJECT", query: "status:open", pageSize: 50, pageStartIndex: 0 },
});
Architecture
src/
config.ts — API base URL, token and per-request token context
server.ts — shared MCP server factory (transport-agnostic)
tools.ts — generated MCP tool definitions (284 tools)
executor.ts — tool call dispatcher
mcp-http-server.ts — Streamable HTTP MCP transport (remote clients)
http-server.ts — plain REST wrapper for ChatGPT Custom GPT Actions
index.ts — stdio entry point (local MCP clients)
polarion.ts — server instructions, guide resources and prompts
auth.ts — authentication helpers
utils.ts — shared utilities
Design notes:
- Tools are auto-generated from the Polarion OpenAPI spec via
npm run regenerate. - REST paths may differ across Polarion versions; regenerate the tools from your instance's OpenAPI spec (
npm run regenerate). - No caching by design. Retries only on 429/5xx with short backoff.
- Bearer token is automatically sanitized from all logs and error messages.
Security
- No stored credentials in HTTP mode — the server keeps no Polarion token of its own; every
/mcprequest carries the caller's own Polarion PAT, or an access token from the OAuth login that carries the PAT encrypted underMCP_TOKEN_SECRET(the client cannot read it), and Polarion authorizes each call under that user - Serve it over TLS — the PAT travels in the request header; terminate TLS in front of the server and bind the plaintext port to loopback (
MCP_HTTP_HOST=127.0.0.1) - DNS-rebinding protection — optional
MCP_ALLOWED_HOSTSallow-list validates theHostheader on every request - OAuth redirect allowlist — client registration is open;
MCP_ALLOWED_REDIRECT_PREFIXESlimits which callbacks may receive a login, so nobody can phish a PAT through a genuine login link on your domain - Server-side tool filter —
MCP_TOOLS/MCP_READ_ONLYremove tools entirely (not listed, not callable) - No Secrets in Logs — tokens are automatically removed from all log output and error messages
Contributing
Contributions are welcome. To get started:
npm install
npm run typecheck # TypeScript check
npm run build # compile to build/
npm run dev:http # run locally
To regenerate tools from the latest Polarion OpenAPI spec:
npm run regenerate # downloads spec, generates tools, builds, and tests
Please open an issue before submitting a larger change so we can discuss the approach. Pull requests should include a description of what changed and why.
Releasing
Releases are automated by .github/workflows/release.yml:
- Run
npm version X.Y.Zonmain(bumps package.json, package-lock.json and server.json in one commit), then push. - Push the tag
npm versioncreated:git push origin vX.Y.Z. - The workflow builds, tests, and packages the release ZIP, then publishes a GitHub Release for the tag with notes auto-generated from the pull requests merged since the previous tag (from the start of the history for the first release).
Acknowledgements
🙏 Thanks to @Jonasdero, whose work is the foundation this MCP server builds on.
License
MIT © Phillip Bösger
README fetched from the repository 3 days ago. The original is authoritative.