Pekao MCP Server
by xnetcat
README.md
# Pekao MCP Server
A Model Context Protocol (MCP) server for the Pekao Polish API (PolishAPI 2.1.1). This server exposes banking operations as MCP tools that can be used by AI assistants like Claude.
## Features
- **Account Information Service (AIS)**: List accounts, view balances, transaction history
- **Payment Initiation Service (PIS)**: Create domestic, SEPA, and international transfers
- **Confirmation of Funds (CAF)**: Check if funds are available
- **OAuth2 Authorization**: Secure authentication flow
## Prerequisites
- Node.js 18+
- Pekao API credentials (client ID, client secret)
- QSEAL certificate and private key for request signing
## Getting API Credentials
Pekao uses the PolishAPI standard with automatic TPP (Third Party Provider) registration. You need PSD2-compliant certificates to register and use the API.
### 1. Obtain PSD2 Certificates
You need **two separate certificates** (using the same certificate for both purposes is not allowed):
| Certificate | Purpose |
|-------------|---------|
| **QWAC** (Qualified Website Authentication Certificate) | Establishing mutual TLS (mTLS) connection |
| **QSealC** (Qualified Electronic Seal Certificate) | Signing API requests (JWS signatures) |
**Where to obtain certificates:**
For **production**, get certificates from a qualified Trust Service Provider (TSP):
- Krajowa Izba Rozliczeniowa (KIR)
- Asseco Data Systems
- Certum (Asseco)
- Other eIDAS-qualified providers listed on the EU Trusted List
The certificates must contain PSD2 roles in the QC_Statement:
- `PSP_AI` - Account Information Service Provider (AISP) - for AIS
- `PSP_PI` - Payment Initiation Service Provider (PISP) - for PIS
- `PSP_IC` - Payment Instrument Issuing Service Provider (PIISP) - for CAF
- `PSP_AS` - Account Servicing Payment Service Provider (ASPSP)
For **sandbox/testing**, contact Pekao for test certificates or use certificates from a test TSP.
### 2. Register Your Application
Registration is done automatically via the `/auth/v2_1_1.1/register` API endpoint. This MCP server includes a registration tool, but you can also register manually.
**Required for registration:**
- QWAC certificate for mTLS connection
- QSealC certificate for signing the request
- A `software_statement` JWT containing your application details
**Software Statement Structure:**
```json
{
"redirect_uris": ["https://your-app.com/callback"],
"iss": "PSDES-ABC-ABC123",
"client_name": "Your App Name",
"sub_contact_email": "contact@your-company.com",
"logo_uri": "https://your-app.com/logo.png",
"jwks_uri": "https://your-app.com/jwks.json",
"client_desc": "Application description",
"sub": "PL-PFSA-YOUR-LICENSE-NUMBER",
"sub_name": "Your Company Sp. z o.o.",
"scope": "ais ais-accounts pis"
}
```
The `software_statement` must be signed as a JWT using your QSealC certificate.
### 3. Receive Your Credentials
After successful registration, you'll receive:
| Credential | Description |
|------------|-------------|
| `client_id` | Your application's unique identifier |
| `client_secret` | Secret key for authentication |
**Important:** Store these credentials securely. They are only returned once during registration.
### 4. Prepare Certificate Files
Save your certificates in PEM format in the `certs/` directory:
**QSealC Certificate** (`certificate.pem`):
```
-----BEGIN CERTIFICATE-----
MIIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
-----END CERTIFICATE-----
```
**Private Key** (`private-key.pem`):
```
-----BEGIN PRIVATE KEY-----
MIIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
-----END PRIVATE KEY-----
```
### 5. Configure the Key ID
The `PEKAO_KEY_ID` is the `kid` (Key ID) parameter from your QSealC certificate. You can find it:
- In your certificate's metadata
- By checking the certificate with OpenSSL: `openssl x509 -in certificate.pem -text`
- From your TSP's certificate issuance documentation
### Environment Variables Reference
| Variable | Required | Description |
|----------|----------|-------------|
| `PEKAO_CLIENT_ID` | Yes | OAuth2 client identifier from registration |
| `PEKAO_CLIENT_SECRET` | Yes | OAuth2 client secret from registration |
| `PEKAO_ENVIRONMENT` | No | `sandbox` (default) or `production` |
| `PEKAO_CERT_PATH` | Yes | Path to your QSealC certificate (PEM format) |
| `PEKAO_KEY_PATH` | Yes | Path to your private key (PEM format) |
| `PEKAO_KEY_ID` | Yes | Key ID (`kid`) from your QSealC certificate |
| `PEKAO_REDIRECT_URI` | Yes | OAuth2 redirect URI (must match registration) |
### API Endpoints
| Environment | Base URL |
|-------------|----------|
| Sandbox | `https://api.sandbox.pekao.com.pl` |
| Production | `https://api.pekao.com.pl` |
## Installation
```bash
git clone https://github.com/xnetcat/pekao-mcp.git
cd pekao-mcp
npm install
npm run build
```
## Configuration
1. Copy the example environment file:
```bash
cp .env.example .env
```
2. Edit `.env` with your credentials:
```env
PEKAO_CLIENT_ID=your-client-id
PEKAO_CLIENT_SECRET=your-client-secret
PEKAO_ENVIRONMENT=sandbox
PEKAO_CERT_PATH=./certs/certificate.pem
PEKAO_KEY_PATH=./certs/private-key.pem
PEKAO_KEY_ID=your-key-id
PEKAO_REDIRECT_URI=http://localhost:3000/callback
```
3. Place your QSEAL certificate and private key in the `certs/` directory.
## Usage
### Claude Desktop
Add to your Claude Desktop configuration file:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"pekao": {
"command": "node",
"args": ["/path/to/pekao-mcp/dist/index.js"],
"env": {
"PEKAO_CLIENT_ID": "your-client-id",
"PEKAO_CLIENT_SECRET": "your-client-secret",
"PEKAO_ENVIRONMENT": "sandbox",
"PEKAO_CERT_PATH": "/path/to/pekao-mcp/certs/certificate.pem",
"PEKAO_KEY_PATH": "/path/to/pekao-mcp/certs/private-key.pem",
"PEKAO_KEY_ID": "your-key-id",
"PEKAO_REDIRECT_URI": "http://localhost:3000/callback"
}
}
}
}
```
### Claude Code (CLI)
Add to your Claude Code MCP settings:
```bash
claude mcp add pekao node /path/to/pekao-mcp/dist/index.js
```
Or add to your project's `.mcp.json`:
```json
{
"mcpServers": {
"pekao": {
"command": "node",
"args": ["/path/to/pekao-mcp/dist/index.js"],
"env": {
"PEKAO_CLIENT_ID": "your-client-id",
"PEKAO_CLIENT_SECRET": "your-client-secret",
"PEKAO_ENVIRONMENT": "sandbox",
"PEKAO_CERT_PATH": "/path/to/pekao-mcp/certs/certificate.pem",
"PEKAO_KEY_PATH": "/path/to/pekao-mcp/certs/private-key.pem",
"PEKAO_KEY_ID": "your-key-id",
"PEKAO_REDIRECT_URI": "http://localhost:3000/callback"
}
}
}
}
```
### Cursor
Add to Cursor's MCP configuration in Settings > MCP Servers:
```json
{
"pekao": {
"command": "node",
"args": ["/path/to/pekao-mcp/dist/index.js"],
"env": {
"PEKAO_CLIENT_ID": "your-client-id",
"PEKAO_CLIENT_SECRET": "your-client-secret",
"PEKAO_ENVIRONMENT": "sandbox",
"PEKAO_CERT_PATH": "/path/to/pekao-mcp/certs/certificate.pem",
"PEKAO_KEY_PATH": "/path/to/pekao-mcp/certs/private-key.pem",
"PEKAO_KEY_ID": "your-key-id",
"PEKAO_REDIRECT_URI": "http://localhost:3000/callback"
}
}
}
```
### Using npx (after publishing to npm)
```json
{
"mcpServers": {
"pekao": {
"command": "npx",
"args": ["pekao-mcp"],
"env": {
"PEKAO_CLIENT_ID": "your-client-id",
"PEKAO_CLIENT_SECRET": "your-client-secret"
}
}
}
}
```
## Available Tools
### Authorization
| Tool | Description |
|------|-------------|
| `pekao-authorize` | Start OAuth2 authorization flow |
| `pekao-exchange-token` | Exchange authorization code for access token |
| `pekao-refresh-token` | Refresh an expired access token |
| `pekao-set-token` | Manually set an access token |
### Account Information
| Tool | Description |
|------|-------------|
| `pekao-get-accounts` | List all accounts |
| `pekao-get-account` | Get details of a specific account |
| `pekao-get-transactions-done` | Get completed transactions |
| `pekao-get-transactions-pending` | Get pending transactions |
| `pekao-get-transactions-rejected` | Get rejected transactions |
| `pekao-get-transactions-cancelled` | Get cancelled transactions |
| `pekao-get-transactions-scheduled` | Get scheduled transactions |
| `pekao-get-holds` | Get account holds |
| `pekao-get-transaction-detail` | Get details of a specific transaction |
| `pekao-delete-consent` | Remove account access consent |
### Payment Initiation
| Tool | Description |
|------|-------------|
| `pekao-initiate-domestic` | Create a domestic transfer |
| `pekao-initiate-eea` | Create a SEPA/EEA transfer |
| `pekao-initiate-non-eea` | Create an international (non-EEA) transfer |
| `pekao-initiate-tax` | Create a tax payment |
| `pekao-initiate-recurring` | Create a recurring payment |
| `pekao-initiate-bundle` | Create multiple transfers as a bundle |
| `pekao-get-payment` | Get payment status |
| `pekao-get-recurring-payment` | Get recurring payment status |
| `pekao-get-bundle` | Get bundle status |
| `pekao-cancel-payment` | Cancel a payment |
| `pekao-cancel-recurring-payment` | Cancel a recurring payment |
### Confirmation of Funds
| Tool | Description |
|------|-------------|
| `pekao-check-funds` | Check if funds are available on an account |
## Example Usage
Once configured, you can ask Claude to:
- "Show me my Pekao bank accounts"
- "What's my account balance?"
- "List my recent transactions"
- "Transfer 100 PLN to account 12345678901234567890123456"
- "Check if I have 500 PLN available"
## Development
```bash
# Install dependencies
npm install
# Build
npm run build
# Run in development mode
npm run dev
# Test with MCP Inspector
npx @modelcontextprotocol/inspector node dist/index.js
```
## Technical Details
### JWS Signature Format
All API requests require a detached JWS signature in the `X-JWS-SIGNATURE` header. The signature format is:
```
[base64url-encoded-header]..[base64url-encoded-signature]
```
The payload section is empty (detached) to avoid duplicating request data. This MCP server handles JWS signing automatically.
**JWS Header Structure:**
```json
{
"alg": "RS256",
"typ": "JWT",
"kid": "your-key-id",
"x5c": ["base64-encoded-certificate"]
}
```
### Required HTTP Headers
All requests include:
- `X-IBM-Client-Id` - Your client ID
- `X-IBM-Client-Secret` - Your client secret
- `X-JWS-SIGNATURE` - Detached JWS signature
- `X-REQUEST-ID` - UUID v4 for request tracking
- `Authorization: Bearer <token>` - For authenticated endpoints
- `Content-Type: application/json`
- `Accept: application/json`
- `Accept-Encoding: gzip`
- `Accept-Language: pl`
- `Accept-Charset: utf-8`
### Rate Limits
For AIS queries without user presence (automatic queries by TPP):
- Maximum 4 requests per 24 hours per consent
- Transaction history limited to 90 days by default
- Exceeding limits returns `429 Too Many Requests`
### Strong Customer Authentication (SCA)
SCA is performed on Pekao's side using:
- SMS codes
- PeoPay mobile authorization
For multiple-use AIS consents, SCA is required every 90 days.
## API Documentation
This server implements the Pekao Polish API (PolishAPI 2.1.1). For full API documentation, see:
- [Pekao API Portal](https://www.pekao.com.pl/developer)
- [PolishAPI Standard](https://polishapi.org/)
- [PolishAPI Swagger Specification](https://app.swaggerhub.com/apis/ZBP/polish-api/)
## Limitations
Based on Pekao's implementation of PolishAPI:
- **No bundle transfers** for retail customers (only corporate via PekaoBiznes24)
- **No SORBNET2, Blue Cash, or TARGET** payment systems for retail
- **No `getMultiplePayments`** - only for corporate customers
- **No `getTransactionsPending`** for retail customers (Pekao24)
- **No decoupled SCA** - only redirect-based authentication
- **No account list consent flow** - accounts must be specified by TPP
- **CAF service** - currently returns unavailable for all accounts
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues