149 lines
6.5 KiB
Markdown
149 lines
6.5 KiB
Markdown
|
|
# jortt-mcp
|
||
|
|
|
||
|
|
A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server for the
|
||
|
|
[Jortt](https://www.jortt.nl) accounting & invoicing API.
|
||
|
|
|
||
|
|
It exposes the full Jortt REST API — customers, invoices, estimates, expenses,
|
||
|
|
projects, bank accounts, reports, and more — as MCP tools, so an MCP-capable
|
||
|
|
assistant (Claude Desktop, Claude Code, etc.) can read and write your Jortt
|
||
|
|
administration on your behalf.
|
||
|
|
|
||
|
|
The tools are generated directly from Jortt's published
|
||
|
|
[OpenAPI specification](https://api.jortt.nl/swagger_doc), so coverage stays
|
||
|
|
faithful to the API: **82 tools** across every documented resource.
|
||
|
|
|
||
|
|
## How it works
|
||
|
|
|
||
|
|
- The build step downloads the Jortt OpenAPI spec to `src/openapi.json` and
|
||
|
|
bundles it into `dist/`. On startup the server reads that spec, resolves all
|
||
|
|
schema references, and turns every operation into an MCP tool with a proper
|
||
|
|
JSON Schema for its arguments. (If no bundled spec is found, it fetches one
|
||
|
|
live from Jortt as a fallback.)
|
||
|
|
- Authentication uses the OAuth 2.0 **client credentials** grant (the flow Jortt
|
||
|
|
recommends for applications bound to your own administration). The server
|
||
|
|
fetches a bearer token, caches it until shortly before it expires, and
|
||
|
|
transparently refreshes on expiry or a `401`.
|
||
|
|
- Path parameters, query parameters, and JSON request bodies are all handled
|
||
|
|
automatically. Request bodies are passed under a single `body` argument.
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
1. A [Jortt account](https://app.jortt.nl/van-start).
|
||
|
|
2. A registered API application. Create one under
|
||
|
|
**Profile → API** →
|
||
|
|
[OAuth applications](https://app.jortt.nl/new_profile/api/jortt/oauth_applications/list),
|
||
|
|
selecting the scopes you want to grant. Registration gives you a
|
||
|
|
**Client ID** and **Client secret**.
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git clone https://github.com/deprekated/jortt-mcp.git
|
||
|
|
cd jortt-mcp
|
||
|
|
npm install # runs the build, which downloads the current Jortt OpenAPI spec
|
||
|
|
```
|
||
|
|
|
||
|
|
> The build fetches `https://api.jortt.nl/swagger_doc`, so it needs outbound
|
||
|
|
> network access. Set `JORTT_OPENAPI_URL` to point at a local copy or mirror if
|
||
|
|
> you build offline.
|
||
|
|
|
||
|
|
## Configuration
|
||
|
|
|
||
|
|
The server is configured entirely through environment variables:
|
||
|
|
|
||
|
|
| Variable | Required | Description |
|
||
|
|
| -------------------- | -------- | --------------------------------------------------------------------------- |
|
||
|
|
| `JORTT_CLIENT_ID` | yes | OAuth client ID of your registered application. |
|
||
|
|
| `JORTT_CLIENT_SECRET`| yes | OAuth client secret. |
|
||
|
|
| `JORTT_SCOPES` | no | Space-separated scopes to request. Defaults to all scopes; the token server only grants scopes your application was registered with. |
|
||
|
|
| `JORTT_OPENAPI_URL` | no | Override the OpenAPI spec source (used at build time and as a runtime fallback). Defaults to `https://api.jortt.nl/swagger_doc`. |
|
||
|
|
|
||
|
|
### Claude Desktop / Claude Code
|
||
|
|
|
||
|
|
Add the server to your MCP client configuration (for Claude Desktop, this is
|
||
|
|
`claude_desktop_config.json`):
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"mcpServers": {
|
||
|
|
"jortt": {
|
||
|
|
"command": "node",
|
||
|
|
"args": ["/absolute/path/to/jortt-mcp/dist/index.js"],
|
||
|
|
"env": {
|
||
|
|
"JORTT_CLIENT_ID": "your-client-id",
|
||
|
|
"JORTT_CLIENT_SECRET": "your-client-secret"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Restrict what the assistant can do by narrowing the scopes:
|
||
|
|
|
||
|
|
```json
|
||
|
|
"env": {
|
||
|
|
"JORTT_CLIENT_ID": "your-client-id",
|
||
|
|
"JORTT_CLIENT_SECRET": "your-client-secret",
|
||
|
|
"JORTT_SCOPES": "invoices:read customers:read reports:read"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Tool overview
|
||
|
|
|
||
|
|
Tool names follow a predictable `verb_resource` convention derived from the API
|
||
|
|
path and version. A selection:
|
||
|
|
|
||
|
|
| Tool | Method & path | What it does |
|
||
|
|
| --------------------------- | ----------------------------------- | ----------------------------------------- |
|
||
|
|
| `list_customers` | `GET /customers` | List / search customers |
|
||
|
|
| `create_customers` | `POST /customers` | Create a customer |
|
||
|
|
| `get_customers` | `GET /customers/{customer_id}` | Fetch a single customer |
|
||
|
|
| `list_invoices` | `GET /invoices` | List / search invoices |
|
||
|
|
| `create_v3_invoices` | `POST /v3/invoices` | Create an invoice (invoice-level VAT) |
|
||
|
|
| `send_invoices` | `POST /invoices/{id}/send` | Send an invoice |
|
||
|
|
| `get_invoices_download` | `GET /invoices/{id}/download` | Get a download URL for the invoice PDF |
|
||
|
|
| `list_v2_estimates` | `GET /v2/estimates` | List estimates |
|
||
|
|
| `create_v2_estimates` | `POST /v2/estimates` | Create an estimate |
|
||
|
|
| `list_v3_expenses` | `GET /v3/expenses` | List expenses |
|
||
|
|
| `list_v3_bank_accounts` | `GET /v3/bank-accounts` | List bank accounts |
|
||
|
|
| `get_reports_summaries_profit_and_loss` | `GET /reports/summaries/profit_and_loss` | Dashboard profit & loss summary |
|
||
|
|
| `get_organizations_me` | `GET /organizations/me` | The organization tied to your credentials |
|
||
|
|
|
||
|
|
Newer resources are versioned (`v2`, `v3`) and the version is part of the tool
|
||
|
|
name. Where Jortt offers multiple versions of the same operation (for example
|
||
|
|
invoice creation), prefer the highest version unless you have a reason not to —
|
||
|
|
`create_v3_invoices` supports invoice-level VAT.
|
||
|
|
|
||
|
|
Run the server and call `tools/list` to see the full, always-current set with
|
||
|
|
per-tool argument schemas.
|
||
|
|
|
||
|
|
## Development
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npm run build # compile TypeScript to dist/ (and copy the spec)
|
||
|
|
npm run dev # tsc --watch
|
||
|
|
npm run typecheck # type-check without emitting
|
||
|
|
```
|
||
|
|
|
||
|
|
### Updating to the latest API
|
||
|
|
|
||
|
|
The tool set is generated from the OpenAPI spec, which the build downloads
|
||
|
|
fresh each time. To pick up new Jortt endpoints, just rebuild:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
No code changes are needed — new operations become new tools automatically.
|
||
|
|
|
||
|
|
## Notes & limits
|
||
|
|
|
||
|
|
- Jortt rate-limits the API to ~10 requests/second. List endpoints paginate at a
|
||
|
|
maximum of 100 items per page (`page` argument).
|
||
|
|
- This is an unofficial, community project and is not affiliated with or endorsed
|
||
|
|
by Jortt.
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
MIT — see [LICENSE](LICENSE).
|