JouloDocs

AI assistants (MCP)

Connect Claude, ChatGPT, Cursor or Claude Code to your Joulo account with the Joulo MCP server

The Joulo MCP server lets an AI assistant read your own Joulo data: your chargers, your charging sessions, your energy totals, your ERE position, your energy contract and today's and tomorrow's electricity prices. You can then ask questions such as "how much did I charge in September?" or "when is power cheapest tonight?" in plain language.

The server speaks the Model Context Protocol. Any assistant that supports remote MCP servers can use it.

https://joulo.nl/mcp

The tools only read. An assistant cannot change your account, start or stop a session, or touch your chargers through this server.

Connect your assistant

Claude

  1. Open Settings → Connectors and choose Add custom connector.
  2. Enter https://joulo.nl/mcp as the URL.
  3. Choose Connect. Claude opens joulo.nl. Sign in and allow access.

ChatGPT

ChatGPT adds a custom MCP server through developer mode. OpenAI offers it on paid plans and often renames the menus, so check the OpenAI help center if a step looks different.

  1. Open Settings → Apps. Under Advanced settings, turn on Developer mode. On a Business or Enterprise workspace, an admin enables it first.
  2. Choose Create app. Enter Joulo as the name and https://joulo.nl/mcp as the URL, and choose OAuth as the authentication.
  3. ChatGPT opens joulo.nl. Sign in and allow access.
  4. In a new chat, open + → Developer mode and select Joulo.

ChatGPT can ask you to confirm a tool call before it runs.

Claude Code

claude mcp add --transport http joulo https://joulo.nl/mcp

Then run /mcp in Claude Code and choose joulo to sign in.

Other assistants

Add a custom connector or remote MCP server with the URL https://joulo.nl/mcp. The assistant registers itself, sends you to joulo.nl to sign in, and stores the token. For Cursor, add this to .cursor/mcp.json:

{
  "mcpServers": {
    "joulo": { "url": "https://joulo.nl/mcp" }
  }
}

With a personal API token

A client that cannot sign in with OAuth can send a personal API token as a header instead:

claude mcp add --transport http joulo https://joulo.nl/mcp --header "Authorization: Bearer YOUR_TOKEN"

A personal token gives the assistant every tool. Partner API keys and CPO tokens do not work here.

Example: what did I earn this year?

Ask the question the way you would ask a person. This example uses ChatGPT and the sample data from the API reference.

You: How much have I earned with Joulo this year, and what is still on its way?

ChatGPT picks the tool that answers money questions and calls it:

{ "name": "get_ere_position", "arguments": { "year": 2026 } }

Joulo returns your position for 2026. An excerpt:

{
  "compliance_year": 2026,
  "effective_fee_pct": 20,
  "paid":     { "ere": 120,   "net_eur": 44.35 },
  "payable":  { "ere": 40,    "net_eur": 14.78 },
  "reserved": { "ere": 60,    "net_eur": 22.12 },
  "unsold":   { "ere": 92.45, "forecast_net_eur": 33.36 },
  "pending_sessions": 2,
  "pending_forecast_net_eur": 3,
  "total_expected_eur": 117.61
}

ChatGPT: So far this year Joulo paid you € 44.35 for 120 ERE. Another € 14.78 is ready for your next quarterly payout, and € 22.12 is reserved in a sale. The 92 ERE that are not sold yet are worth about € 33 at today's price. Two recent sessions, worth about € 3, are still being checked. For 2026 you can expect about € 118 in total, after your 20% service fee.

The assistant answers in the language you write in. Ask in Dutch and you get Dutch.

A forecast of € 0 while the quarters show production means a step of your registration is still open. The position then carries blocked, with the step in reason (registration, mandate, ean, review or iban) and the ERE and euro amount waiting on it. The tool description tells the assistant to read that field, so it answers "387 ERE wait until you confirm that this station sits behind your connection" instead of "€ 0".

More questions to try

QuestionTools the assistant uses
How many kWh did I charge in September?list_charging_sessions
Which of my sessions last month did not count for ERE, and why?list_charging_sessions, list_chargers
Is my charging station charging right now?list_chargers
Show my kWh per month this year as a table.get_energy_totals
What service fee do I pay?get_account
What do I still have to do before Joulo pays me?get_registration_status
When is power cheapest tomorrow?get_price_curve
What does a kWh cost me tonight after my ERE?get_price_curve
Which supplier and contract does Joulo have for me?get_household
What do Joulo customers get per kWh?get_ere_market
I need 30 kWh by 7:00. When should I charge?find_cheapest_window
What did charging cost me in September, and what would smart charging have saved?get_charging_costs
How do I connect my Alfen?get_connection_guide
Does my charger need a MID meter?read_kennisbank_article
How do I charge without a card again?get_feature_guide

Sign-in and permissions

The first time you connect, joulo.nl shows a consent screen. It names the assistant, says that Joulo has not reviewed it, and lists what it may read. The name on that screen is the name the assistant gave itself. Only allow access if you just started the connection yourself.

ScopeWhat the assistant may read
profile:readYour name, email address and service fee, your energy contract, your household answers, your electricity prices and your charging costs
locations:readThe postcode and city of your addresses. Never your street or house number.
chargers:readYour chargers and their status
sessions:readYour charging sessions
energy:readYour energy totals and ERE
position:readYour ERE reserve, sales, payouts and forecast, and where your registration stands

To stop the access, open your dashboard at Developer → API → Connected apps and revoke the assistant. Its tokens stop working on the next request.

Tools

ToolScopeReturns
get_accountprofile:readName, email, effective service fee and the indicative ERE price behind the estimates. Same data as GET /me.
list_chargerschargers:readYour chargers with their brand and model, whether Joulo hears from each one, whether each one counts for ERE, and any session that charges right now. Same data as GET /chargers.
list_charging_sessionssessions:readSessions, newest first, filtered by period and charger, 100 per page at most. Same data as GET /sessions.
get_energy_totalsenergy:readLifetime and monthly kWh, ERE and session counts. Same data as GET /energy.
get_ere_positionposition:readReserved, sold, payable and paid ERE for one year, with the forecast per quarter. Same data as GET /ere-position.
get_registration_statusposition:readPer step what is done and what is still open before Joulo can sell your ERE: a charger that counts, the form, the mandate, the EAN, Joulo's review and the IBAN. Same data as GET /registration-status.
get_price_curveprofile:readThe electricity price of one day per hour or per 15 minutes: spot, the price on a dynamic contract with your supplier, your own price, and the price after ERE. Same data as GET /prices. Shows a chart in assistants that support MCP Apps or ChatGPT apps.
get_householdprofile:readYour energy contract and your household answers. Same data as GET /household.
list_locationslocations:readThe postcode and city of each of your addresses. Same data as GET /locations.
find_cheapest_windowprofile:readWhen to charge a number of kWh most cheaply before a deadline: the cheapest slots, the cheapest stretch without a pause, and starting now, each with its cost. Same data as GET /prices/cheapest-window.
get_charging_costsprofile:readWhat charging cost over a period on your contract, what smart charging would have cost, and the ERE against it. Same data as GET /costs.
get_ere_marketnoneThe one indicative ERE price for what is not sold yet, plus the customer average and the sales log as history. Same data as GET /ere-market.
read_kennisbank_articlenoneOne article from the public kennisbank, with its live figures. Same data as GET /kennisbank-article.
get_connection_guidenoneJoulo's manual for connecting a charger of one brand, with the link to it on joulo.nl/docs. Same data as GET /connection-guide.
get_feature_guidenoneHow a feature of the Joulo dashboard or app works: where it is, what it does, and what only the Joulo team can do. Same data as GET /feature-guide.

list_charging_sessions takes from and to as an ISO 8601 date or date-time. A bare date means the start or the end of that day in Amsterdam, so from: 2026-09-01, to: 2026-09-30 covers all of September.

get_price_curve takes day (today, tomorrow or a date) and resolution (60 or 15 minutes). Tomorrow's prices exist after the daily publication in the early afternoon. Before that, the tool says when they come.

Every estimate uses one ERE price: the indicative price per ERE that your dashboard forecast uses. Realized sale prices appear only as history, in get_ere_market. A blocked step in get_ere_position comes with a link to the article that explains it and to the dashboard tab where you complete it.

The assistant sees only the tools your scopes allow. One exception: a connection made before locations:read existed still sees list_locations. The first call asks you to allow that scope on joulo.nl. Every tool call counts toward the same rate limit as a REST call.

For client developers

  • Transport: Streamable HTTP. Send each JSON-RPC message with POST. The server answers with application/json and keeps no session, so GET and DELETE return 405.
  • Step-up: a call to a tool behind a scope added after you connected (now only locations:read) answers 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="…". The scope parameter lists every scope the token holds plus the missing one, so request that whole set. In a JSON-RPC batch the same call returns a tool error instead.
  • Widgets: get_price_curve carries a UI resource. MCP Apps hosts read _meta.ui.resourceUri (ui://joulo/price-curve.html, text/html;profile=mcp-app). ChatGPT reads openai/outputTemplate (ui://joulo/price-curve.skybridge.html, text/html+skybridge). Both serve the same HTML, which loads nothing from the network and reads the tool's structuredContent. The server lists both under resources/list.
  • Protocol versions: 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05.
  • Discovery: a request without a valid token returns 401 with WWW-Authenticate: Bearer resource_metadata="https://joulo.nl/.well-known/oauth-protected-resource/mcp". The authorization server metadata is at https://joulo.nl/.well-known/oauth-authorization-server.
  • Client registration: POST https://api.joulo.nl/functions/v1/oauth-register (RFC 7591). A client registers as public (token_endpoint_auth_method: none) unless it asks for a secret. A self-registered client can only hold the read scopes above. Redirect URIs must use https, http on localhost, or an app scheme. A client that nobody authorizes within 30 days is deleted.
  • Authorization: the code flow with PKCE (S256). See OAuth2. Without a scope parameter, a self-registered client gets all of its scopes, and the user decides on the consent screen.