# Jurnal Mcp

> Read-only MCP server for Mekari Jurnal accounting API (jurnal.id) — 27 tools, HMAC-SHA256 auth, multi-profile support, financial-report PDF generator.

- **Type:** MCP server
- **Install:** `agentstack add mcp-teguhcanggu-jurnal-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Teguhcanggu](https://agentstack.voostack.com/s/teguhcanggu)
- **Installs:** 0
- **Category:** [Content & Media](https://agentstack.voostack.com/c/content-and-media)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Teguhcanggu](https://github.com/Teguhcanggu)
- **Source:** https://github.com/Teguhcanggu/jurnal-mcp
- **Website:** https://github.com/Teguhcanggu/jurnal-mcp

## Install

```sh
agentstack add mcp-teguhcanggu-jurnal-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# jurnal-mcp

[](LICENSE)
[](https://www.python.org/)

Read-only [Model Context Protocol](https://modelcontextprotocol.io/) server
for the [Mekari Jurnal](https://www.jurnal.id/) accounting API. Lets MCP
clients (Claude Code, Claude Desktop, etc.) read contacts, invoices, journal
entries, and financial reports across one or more Jurnal companies.

> **Read-only by design.** No tool in this server creates, updates, or
> deletes data in Jurnal. Use it to read accounting facts and let the AI
> assemble accurate reports from them.

## Features

- 27 MCP tools covering master data, transactions, and 8 financial reports
  (P&L, balance sheet, cash flow, trial balance, GL, aged AP/AR, executive
  summary)
- HMAC-SHA256 request signing per Mekari's official auth scheme — stateless,
  no token refresh, no OAuth flow
- Multi-profile support: connect several Jurnal companies/credentials and
  switch per call via a `profile` argument
- Python 3.11+, [`uv`](https://github.com/astral-sh/uv) packaged,
  [FastMCP](https://github.com/jlowin/fastmcp) transport

## Requirements

- Python ≥ 3.11
- [`uv`](https://docs.astral.sh/uv/) for dependency management
- A Mekari developer application with `Client ID` + `Client Secret` per
  Jurnal company you want to access. Apply or check yours at
  [developers.mekari.com](https://developers.mekari.com/).

## Install

```bash
git clone https://github.com//jurnal-mcp.git
cd jurnal-mcp/jurnal-mcp-server
uv sync
```

## Configure

Copy the example env file and fill in your credentials:

```bash
cp ../.env.example .env   # path is relative to jurnal-mcp-server/
```

Edit `jurnal-mcp-server/.env`:

```env
JURNAL_PROFILE_MAIN_CLIENT_ID=
JURNAL_PROFILE_MAIN_CLIENT_SECRET=
JURNAL_DEFAULT_PROFILE=main
```

To connect more than one Jurnal company, add more profiles by repeating the
pattern with a different ``:

```env
JURNAL_PROFILE_BRANCH_A_CLIENT_ID=...
JURNAL_PROFILE_BRANCH_A_CLIENT_SECRET=...
JURNAL_PROFILE_BRANCH_B_CLIENT_ID=...
JURNAL_PROFILE_BRANCH_B_CLIENT_SECRET=...
```

`` is any uppercase identifier you choose. Each tool accepts an
optional `profile` argument that selects which credentials to use; calls
without an explicit `profile` fall back to `JURNAL_DEFAULT_PROFILE`.

> **Security:** keep `.env` gitignored, restrict permissions
> (`chmod 600 .env`), and never commit credentials. The `.gitignore`
> already excludes `.env`.

## Run as a standalone MCP server

```bash
cd jurnal-mcp-server
uv run main.py
```

The server speaks MCP over stdio.

## Add to Claude Code

Add this entry to your `~/.claude/mcp.json` (or the equivalent for your MCP
host):

```json
{
  "mcpServers": {
    "jurnal": {
      "type": "stdio",
      "command": "/path/to/uv",
      "args": [
        "--directory",
        "/absolute/path/to/jurnal-mcp/jurnal-mcp-server",
        "run",
        "main.py"
      ],
      "env": {
        "JURNAL_PROFILE_MAIN_CLIENT_ID": "...",
        "JURNAL_PROFILE_MAIN_CLIENT_SECRET": "...",
        "JURNAL_DEFAULT_PROFILE": "main"
      }
    }
  }
}
```

You can also keep credentials in `jurnal-mcp-server/.env` and omit the `env`
block — the server loads `.env` automatically on startup.

## Available tools (27)

All tools are read-only (`GET`). Every tool takes an optional
`profile: str | None` argument; omit to use `JURNAL_DEFAULT_PROFILE`.

### Auth & discovery

| Tool | Endpoint | Description |
|------|----------|-------------|
| `list_profiles` | (local) | Profiles discovered from env vars + the default |
| `whoami` | `GET /api/v1/users/me` | Authenticated Mekari user |
| `get_active_company` | `GET /api/v1/companies/active` | Active company for the credentials |
| `list_companies` | `GET /api/v1/companies` | Companies accessible to the credentials |

### Master data

| Tool | Endpoint |
|------|----------|
| `list_contacts(contact_index?)` | `GET /api/v1/contacts` |
| `get_contact(id)` | `GET /api/v1/contacts/{id}` |
| `list_customers(page?, page_size?, sort_key?, sort_order?)` | `GET /api/v1/customers` |
| `list_vendors(page?, page_size?, sort_key?, sort_order?)` | `GET /api/v1/vendors` |
| `list_products(include_archive?)` | `GET /api/v1/products` |
| `list_accounts(include_archive?)` | `GET /api/v1/accounts` (chart of accounts) |

### Transactions

| Tool | Endpoint |
|------|----------|
| `list_sales_invoices(page?, page_size?, sort_key?, sort_order?)` | `GET /api/v1/sales_invoices` |
| `get_sales_invoice(id)` | `GET /api/v1/sales_invoices/{id}` |
| `list_purchase_invoices(page?, page_size?, sort_key?, sort_order?)` | `GET /api/v1/purchase_invoices` |
| `get_purchase_invoice(id)` | `GET /api/v1/purchase_invoices/{id}` |
| `list_journal_entries()` | `GET /api/v1/journal_entries` |
| `get_journal_entry(id)` | `GET /api/v1/journal_entries/{id}` |
| `list_expenses()` | `GET /api/v1/expenses` |
| `list_receive_payments()` | `GET /api/v1/receive_payments` |
| `list_purchase_payments()` | `GET /api/v1/purchase_payments` |

### Financial reports

All report endpoints accept dates in **`dd/mm/yyyy`** form (e.g.
`"01/01/2026"`).

| Tool | Endpoint |
|------|----------|
| `get_profit_and_loss(start_date, end_date, period?, compare_type?)` | `GET /api/v1/profit_and_loss` |
| `get_balance_sheet(end_date, compare?, period?, compare_type?)` | `GET /api/v1/balance_sheet` |
| `get_cash_flow(start_date, end_date, period?, compare_type?)` | `GET /api/v1/cash_flow` |
| `get_general_ledger(start_date, end_date, account_id?, compare_type?)` | `GET /api/v1/general_ledger` |
| `get_trial_balance(start_date?, end_date?, period?, compare_type?)` | `GET /api/v1/trial_balance` |
| `get_aged_payables(end_date?, period?, compare_type?)` | `GET /api/v1/aged_payables` |
| `get_aged_receivables(end_date?, period?, compare_type?)` | `GET /api/v1/aged_receivables` |
| `get_executive_summary(start_date?, end_date?, period?, compare_type?)` | `GET /api/v1/executive_summary` |

`compare_type` accepts: `custom`, `day`, `week`, `month`, `year`,
`yesterday`, `last_week`, `last_month`, `last_year`.

## Authentication scheme (HMAC)

Every request is signed with HMAC-SHA256 over a canonical string:

```
date: 
  HTTP/1.1
```

The two lines are joined by `\n`. The signature is base64-encoded and sent
in the `Authorization` header alongside `Date`:

```
Date: Wed, 29 Apr 2026 03:00:00 GMT
Authorization: hmac username="", algorithm="hmac-sha256", headers="date request-line", signature=""
```

Mekari rejects requests whose `Date` differs from server time by more than
**300 seconds**. Make sure the host clock is in sync (e.g. via NTP).

This server only signs `GET` requests, so the `Digest` header that Mekari
requires for write methods is not sent. Adding write tools is intentionally
out of scope.

References:
- [Mekari HMAC authentication docs](https://developers.mekari.com/docs/kb/hmac-authentication)
- [Official PHP example](https://github.com/mekari-engineering/mekari-api-hmac-example-php)

## Multi-profile usage examples

```python
# In an MCP client conversation:
# 1) Discover profiles
list_profiles()
# -> {"profiles": ["branch_a", "branch_b", "main"], "default": "main"}

# 2) Read a specific company's profit & loss (dates in dd/mm/yyyy)
get_profit_and_loss(
    profile="branch_a",
    start_date="01/01/2026",
    end_date="31/03/2026",
)

# 3) List contacts from another profile
list_contacts(profile="branch_b")
```

If only one Mekari Client ID gives access to multiple companies, you can
configure a single profile and skip the `profile` argument entirely.

## Development

Install dev dependencies and run the offline test suite:

```bash
cd jurnal-mcp-server
uv sync --all-extras --dev
uv run pytest tests/ -v
```

The test suite verifies the HMAC string-to-sign matches Mekari's reference
implementation, exercises the path/query construction, and the profile
resolver. It does not call the live API.

## Verifying tools end-to-end

After credentials are in place, a quick smoke test:

```bash
uv run python -c "from jurnal import JurnalClient; print(JurnalClient.from_profile().get('/api/v1/users/me'))"
```

A `200` response with user info confirms credentials and signing work. A
`401` usually means a clock skew over 300 seconds, a wrong client ID, or a
secret with whitespace.

## Status & limitations

- **Read-only.** No write tools are exposed; the server signs only `GET`.
- **Date format.** All report tools take dates in `dd/mm/yyyy` form. The
  swagger spec only documents this format explicitly for `general_ledger`,
  but in practice the same format works across the report endpoints, so
  this server uses it uniformly for predictability.
- **No retry/backoff** on rate limits yet; add as needed for your workload.

## License

MIT — see [`LICENSE`](LICENSE).

## Acknowledgements

- [Mekari Engineering's HMAC example](https://github.com/mekari-engineering/mekari-api-hmac-example-php)
  for the reference signing flow.
- [FastMCP](https://github.com/jlowin/fastmcp) for the MCP plumbing.

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Teguhcanggu](https://github.com/Teguhcanggu)
- **Source:** [Teguhcanggu/jurnal-mcp](https://github.com/Teguhcanggu/jurnal-mcp)
- **License:** MIT
- **Homepage:** https://github.com/Teguhcanggu/jurnal-mcp

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-teguhcanggu-jurnal-mcp
- Seller: https://agentstack.voostack.com/s/teguhcanggu
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
