An MCP server exposing pyxirr financial calculation functions as tools
Project description
PyXIRR MCP Server
A Model Context Protocol (MCP) server that exposes pyxirr financial calculation functions as tools for use with GitHub Copilot and other MCP clients.
Features
This MCP server provides the following financial calculation tools:
Rate of Return Functions
- xirr - Extended Internal Rate of Return for irregular cash flows
- irr - Internal Rate of Return for periodic cash flows
- mirr - Modified Internal Rate of Return
Net Present/Future Value Functions
- xnpv - Net Present Value for irregular cash flows
- npv - Net Present Value for periodic cash flows
- xnfv - Net Future Value for irregular cash flows
- nfv - Net Future Value for periodic cash flows
Time Value of Money Functions
- fv - Future Value
- pv - Present Value
- pmt - Payment calculation
- nper - Number of periods
- rate - Interest rate calculation
Loan Analysis Functions
- ipmt - Interest portion of a payment
- ppmt - Principal portion of a payment
- cumipmt - Cumulative interest paid
- cumprinc - Cumulative principal paid
Installation
Prerequisites
- Python 3.10 or higher
- pip or uv package manager
Install from source
cd pyxirr-mcp-server
pip install -e .
Or with uv:
cd pyxirr-mcp-server
uv pip install -e .
Configuration
GitHub Copilot (VS Code) - Recommended
Create a .vscode/mcp.json file in your workspace (this is included in the project):
{
"servers": {
"pyxirr": {
"type": "stdio",
"command": "python",
"args": ["-m", "pyxirr_mcp_server.server"],
"cwd": "${workspaceFolder}/src"
}
}
}
This follows the VS Code MCP developer guidelines.
Alternative: Global VS Code settings
Add to your VS Code settings.json:
{
"github.copilot.chat.mcpServers": {
"pyxirr": {
"command": "python",
"args": ["-m", "pyxirr_mcp_server.server"],
"cwd": "/path/to/pyxirr-mcp-server/src"
}
}
}
Claude Desktop
Add to your Claude Desktop configuration (claude_desktop_config.json):
{
"mcpServers": {
"pyxirr": {
"command": "python",
"args": ["-m", "pyxirr_mcp_server.server"],
"cwd": "/path/to/pyxirr-mcp-server/src"
}
}
}
Usage Examples
Once configured, you can ask GitHub Copilot to perform financial calculations:
XIRR Calculation
"Calculate the XIRR for an investment of $10,000 on January 1, 2020, with returns of $5,750 on March 1, 2020, $4,250 on October 30, 2020, and $3,250 on February 15, 2021"
Mortgage Payment
"What's the monthly payment for a $300,000 mortgage at 6.5% annual rate over 30 years?"
Investment Future Value
"If I invest $500 per month for 20 years at 7% annual return, what will be the future value?"
NPV Analysis
"Calculate the NPV at 10% discount rate for an investment of $50,000 with annual returns of $15,000, $18,000, $20,000, and $22,000"
Cash Flow Conventions
Important: By convention in financial calculations:
- Negative values represent money going OUT (investments, deposits, payments)
- Positive values represent money coming IN (returns, income, withdrawals)
API Reference
All tools use camelCase parameter names following VS Code MCP guidelines.
xirr(dates, amounts, guess?)
Calculate the Internal Rate of Return for irregular cash flows.
xnpv(rate, dates, amounts)
Calculate the Net Present Value for irregular cash flows.
irr(amounts, guess?)
Calculate the Internal Rate of Return for periodic cash flows.
npv(rate, amounts, startFromZero?)
Calculate the Net Present Value for periodic cash flows.
mirr(amounts, financeRate, reinvestRate)
Calculate the Modified Internal Rate of Return.
fv(rate, nper, pmt, pv, pmtAtBeginning?)
Calculate the Future Value.
pv(rate, nper, pmt, fv?, pmtAtBeginning?)
Calculate the Present Value.
pmt(rate, nper, pv, fv?, pmtAtBeginning?)
Calculate the periodic Payment.
nper(rate, pmt, pv, fv?, pmtAtBeginning?)
Calculate the Number of Periods.
rate(nper, pmt, pv, fv?, pmtAtBeginning?, guess?)
Calculate the interest Rate per period.
ipmt(rate, per, nper, pv, fv?, pmtAtBeginning?)
Calculate the Interest portion of a specific payment.
ppmt(rate, per, nper, pv, fv?, pmtAtBeginning?)
Calculate the Principal portion of a specific payment.
cumipmt(rate, nper, pv, startPeriod, endPeriod, pmtAtBeginning?)
Calculate Cumulative Interest paid between periods.
cumprinc(rate, nper, pv, startPeriod, endPeriod, pmtAtBeginning?)
Calculate Cumulative Principal paid between periods.
nfv(rate, nper, amounts)
Calculate Net Future Value for uneven periodic payments.
xnfv(rate, dates, amounts)
Calculate Net Future Value for irregular cash flows.
License
MIT
Publishing
Releases of this package are automated by publish-pyxirr-mcp.yml. The workflow runs three sequential, gated stages:
- test — runs
pytest. Required for everything downstream. - pypi-publish — builds and uploads to PyPI using a project-scoped API token (
PYPI_API_TOKENsecret). - mcp-publish — registers
server.jsonwith the MCP registry usingmcp-publisherand GitHub OIDC.
Releasing a new version
- Bump the version in three places (they must match — the workflow enforces it):
pyxirr-mcp-server/pyproject.toml→[project].versionpyxirr-mcp-server/server.json→ top-levelversionandpackages[0].version
- Merge to
main. - Tag and push:
git tag pyxirr-v0.2.0 git push origin pyxirr-v0.2.0
- The workflow runs end-to-end. Watch it under Actions → "Publish pyxirr-mcp-server".
One-time setup
PyPI API token
Trusted Publishing (OIDC) is not usable in this repo because the b2impact-com GitHub organisation is invisible to PyPI's anonymous GitHub API lookup (likely Enterprise Managed Users). The fallback is a project-scoped PyPI API token, gated by the pypi environment with required reviewers.
First publish (bootstrap, account-scoped token):
- Create a PyPI account if needed and verify you can log in at https://pypi.org/.
- Generate an account-scoped API token at https://pypi.org/manage/account/token/. (Project scope is not available until the project exists on PyPI.)
- In this repo: Settings → Environments →
pypi→ Add secretPYPI_API_TOKENwith the token value. Scope the secret to thepypienvironment, not the repo, so it is only readable while the environment's required reviewer has approved the run. - Run the publish workflow (push a
pyxirr-v0.2.0tag). Approve the environment gate.
After the first successful publish (lock down the token):
- On PyPI: revoke the account-scoped token.
- Generate a new token scoped to the
pyxirr-mcp-serverproject only. - Update the
PYPI_API_TOKENenvironment secret with the new value.
Rotate the project-scoped token periodically (e.g. yearly) or immediately if the secret is ever exposed.
GitHub Actions environments
Two environments gate the release. Create both under Settings → Environments, with the exact names below, and add required reviewers on each:
| Environment | Used by job | Secret |
|---|---|---|
pypi |
pypi-publish |
PYPI_API_TOKEN |
mcp-registry |
mcp-publish |
MCP_REGISTRY_URL |
Keeping them separate means PyPI credentials and the internal registry URL are never loaded into the same job, and each stage requires its own human approval click.
Security hardening (required before first release)
Configure these in repo Settings — they are not version-controlled and must be applied manually:
- Required reviewers on both environments (
pypiandmcp-registry). Every publish stage then requires a human approval click. With token-based auth this is the primary mitigation against secret misuse — without it, any workflow run that reaches a publish job can read the secret. - Scope each secret to its environment, not the repo:
PYPI_API_TOKENonpypi,MCP_REGISTRY_URLonmcp-registry. This way neither secret is readable from any other workflow, job, branch, or PR. - Tag protection rule for
pyxirr-v*(Settings → Rules → Rulesets, target Tags). Restricts who can push release tags. - Branch protection on
main: require PR review + status checks (incl.pyxirr-mcp-server-testsfromci.yml) before merge. - Dependabot is configured (
.github/dependabot.yml) to weekly bump GitHub Actions and Python deps. Review and merge those PRs promptly; the workflow usesmcp-publisherpinned via theMCP_PUBLISHER_VERSIONenv in the workflow file. - Pre-release audit: the
buildjob already lists every file in the wheel + sdist and computes SHA256s. Inspect the workflow log on the first release to confirm only expected files ship.
MCP registry
The target registry URL is supplied via the environment secret MCP_REGISTRY_URL on the mcp-registry environment (Settings → Environments → mcp-registry → Add secret). It points to an internal organisational registry, so it is stored as a secret (masked in workflow logs) and scoped to the publish environment only — not as a repo-wide secret or variable. The workflow fails fast if the secret is missing.
The registry must be configured to accept GitHub OIDC tokens. The server name io.github.b2impact-com/pyxirr-mcp-server matches the OIDC-granted namespace io.github.{org}/*.
Ownership verification
PyPI ownership is verified by the MCP registry via the mcp-name: marker in this README (line 3). The marker is shipped inside the wheel because hatchling includes README.md. Do not remove it.
Credits
This MCP server is powered by pyxirr, a Rust-powered collection of financial functions.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyxirr_mcp_server-0.2.0.tar.gz.
File metadata
- Download URL: pyxirr_mcp_server-0.2.0.tar.gz
- Upload date:
- Size: 14.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a444b312361549aadfb224f092dfa58ab06718de69e3e1913aa5447668ea997d
|
|
| MD5 |
4aadce36aa7cb65bcb8498215acff9c8
|
|
| BLAKE2b-256 |
b2133c230712472168500a432077e63375a62b818b12ec9243f351feacd48da5
|
File details
Details for the file pyxirr_mcp_server-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pyxirr_mcp_server-0.2.0-py3-none-any.whl
- Upload date:
- Size: 9.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44d0e08b61897ea3dd216f06a80eecd336e95ceab8c1156e2da6fbaf82245408
|
|
| MD5 |
a90e2021bf92401221d55228f12bc03f
|
|
| BLAKE2b-256 |
4745580c5e9ce61d30bf2c6a403e2d3af18697c106d9a4d3abb0c5f0eabdb1a5
|