Skip to content

Initial FlexMeasures MCP server#1

Open
Flix6x wants to merge 12 commits into
mainfrom
feat/initial-mcp-server
Open

Initial FlexMeasures MCP server#1
Flix6x wants to merge 12 commits into
mainfrom
feat/initial-mcp-server

Conversation

@Flix6x

@Flix6x Flix6x commented Jul 12, 2026

Copy link
Copy Markdown
Member

What

A FastMCP server over the FlexMeasures API v3_0, built on flexmeasures-client>=0.9, so agents can build and operate complete sites while the FlexMeasures server's auth and permission model stays authoritative.

  • 23 curated tools (26 with the gated delete_asset/delete_automation/authenticate enabled), whose names match the stable operationIds being added to the FlexMeasures OpenAPI spec: connection/health, asset & sensor CRUD, time-series post/read, forecast + schedule trigger/retrieve, uniform job polling (get_job_status), and automations CRUD (create_report_automation for reports, which only run via cron automations).
  • 4 prompts: build_site_and_run_schedule (the full 8-step recipe), add_measurements_and_forecast, setup_report_automation, diagnose_failed_job.
  • Resources: flex-model / flex-context cheat sheets + a pointer to the instance's machine-readable OpenAPI spec.
  • Async-job ergonomics: trigger tools return the job UUID immediately with next-step hints; pending polls return a structured "still running — poll get_job_status" result instead of an error. Works against both the upcoming 202-based API (v3.0-32, Switch forecasting and schedule - triggering endpoints to 202 Accepted flexmeasures#2171) and older servers.
  • Config via env vars (FLEXMEASURES_HOST/EMAIL/PASSWORD/ACCESS_TOKEN/SSL); stdio transport by default, --transport streamable-http for remote mode (single-identity, documented warning).
  • Extensibility: flexmeasures_mcp.tools entry-point group lets plugin packages register extra tools; broken plugins are logged and skipped.
  • Tests: 52 unit tests driving tools through the real MCP protocol (in-memory session, mocked client), plus an opt-in e2e suite (pytest -m e2e) with a self-contained docker-compose stack.
  • Registry-ready: server.json (namespace io.github.flexmeasures/flexmeasures, PyPI + stdio) and the mcp-name: marker in the README.

Verification

  • uv run pytest — 52 passed, 2 deselected.
  • uv run --with pytest-cov pytest --cov=flexmeasures_mcp --cov-report=term-missing — 95% coverage.
  • uv run pytest -m e2e — 2 passed against the Docker Compose FlexMeasures stack.
  • Live smoke against a local Docker dev server: 23 tools advertised, health_check returned FlexMeasures 0.33.2.dev0+gac4f2ca48.d20260703 with SQL/Redis ready, connection_info returned the toy user, and bad credentials returned an MCP tool error.

How to test

gh repo clone FlexMeasures/flexmeasures-mcp
cd flexmeasures-mcp
gh pr checkout 1
uv venv && uv pip install -e ".[test]"
uv run pytest          # unit tests, no FlexMeasures server needed

How to demo

Requires Docker and Claude Code (or any MCP client; see below for MCP Inspector).

1. Start a throwaway FlexMeasures stack (own Postgres + Redis + worker, on port 5001) and seed the toy account:

docker compose -f tests/e2e/docker-compose.yml up -d
docker compose -f tests/e2e/docker-compose.yml exec server \
  flexmeasures add toy-account --kind battery

2. Register the MCP server (from the repo root, so "$PWD" points at your clone):

claude mcp add flexmeasures \
  -e FLEXMEASURES_HOST=localhost:5001 -e FLEXMEASURES_SSL=false \
  -e FLEXMEASURES_EMAIL=toy-user@flexmeasures.io \
  -e FLEXMEASURES_PASSWORD=toy-password \
  -- uv --directory "$PWD" run flexmeasures-mcp

3. Demo. In Claude Code, try:

Using the flexmeasures tools: build a site called "Demo plant" with a 900 kWh / 500 kW battery, post plausible hourly day-ahead prices for tomorrow, and compute an optimized charging schedule. Summarize the created IDs, job UUIDs and the schedule.

or invoke the bundled build_site_and_run_schedule prompt. Expect the agent to walk through create_assetcreate_sensorpost_sensor_datatrigger_scheduleget_job_status polling → get_schedule, and to explain the result (charging in the cheap hours). Also fun: ask it to break something (e.g. an impossible soc-max) and then to run the diagnose_failed_job prompt.

Without Claude: npx @modelcontextprotocol/inspector lets you poke at the tools directly — set the same FLEXMEASURES_* env vars and use uv run flexmeasures-mcp as the command.

4. End-to-end test suite against the same stack:

FLEXMEASURES_E2E_HOST=localhost:5001 \
FLEXMEASURES_E2E_EMAIL=toy-user@flexmeasures.io \
FLEXMEASURES_E2E_PASSWORD=toy-password \
uv run pytest -m e2e

The e2e schedule smoke test defaults to a short schedule horizon; tune it with FLEXMEASURES_E2E_SCHEDULE_HOURS, FLEXMEASURES_E2E_POLL_SECONDS, and FLEXMEASURES_E2E_POLL_ATTEMPTS if needed.

Clean up with docker compose -f tests/e2e/docker-compose.yml down -v.

🤖 Generated with Claude Code

https://claude.ai/code/session_0199yMJvFFPK5HyQRJAMpHpU

@socket-security

socket-security Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpandas@​2.3.37610010010080
Addedpandas@​3.0.37610010010080
Addedpytest@​9.1.187100100100100
Addedaiohttp@​3.14.197100100100100
Addedflexmeasures-client@​0.9.299100100100100
Addedmcp@​1.28.199100100100100
Addedpydantic@​2.13.4100100100100100
Addedpytest-asyncio@​1.4.0100100100100100
Addedpydantic-settings@​2.14.2100100100100100

View full report

@socket-security

socket-security Bot commented Jul 12, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: pypi numpy is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: uv.lockpypi/pandas@3.0.3pypi/pandas@2.3.3pypi/numpy@2.5.1

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/numpy@2.5.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: pypi pycparser is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: uv.lockpypi/pycparser@3.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pycparser@3.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: pypi pycparser is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: uv.lockpypi/pycparser@3.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pycparser@3.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Flix6x and others added 3 commits July 12, 2026 07:14
FastMCP server over the FlexMeasures API v3_0, built on flexmeasures-client:
- 23 curated tools (26 with gated delete/authenticate) whose names match
  the stable operationIds in the FlexMeasures OpenAPI spec
- prompts for the core workflows (build site + schedule, forecast,
  report automation, failed-job diagnosis) and flex-model/context resources
- env-based credentials; stdio (default) and streamable-http transports
- ExtendedFlexMeasuresClient adds forecasts, jobs, automations and health
  endpoints, accepting both 202 (API v3.0-32+) and 200 (older servers)
- unit tests through the MCP protocol; opt-in e2e suite with its own
  docker-compose stack
- server.json for the MCP registry (PyPI package, stdio)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199yMJvFFPK5HyQRJAMpHpU

Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199yMJvFFPK5HyQRJAMpHpU
Signed-off-by: F.N. Claessen <felix@seita.nl>
Plain pytest collects e2e modules before deselecting them by marker,
and the relative conftest import breaks that collection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199yMJvFFPK5HyQRJAMpHpU
Signed-off-by: F.N. Claessen <felix@seita.nl>
@Flix6x
Flix6x force-pushed the feat/initial-mcp-server branch from 92714d5 to 94cfa4a Compare July 12, 2026 05:14
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
@BelhsanHmida

Copy link
Copy Markdown

Pushed follow-up fixes and test coverage improvements:

  • Fixed the e2e Docker worker queue command so the worker starts correctly.
  • Added e2e server readiness checks before live MCP calls.
  • Made the e2e schedule smoke test lighter and configurable to avoid worker timeout flakiness.
  • Replaced deprecated pandas UTC timestamp usage.
  • Fixed non-JSON FlexMeasures API response handling.
  • Added focused unit coverage for CLI behavior, client edge cases, error mapping, MCP tool payloads, gated tools, prompts/resources, and plugin loading.

Verification:

  • uv run pytest — 52 passed, 2 deselected
  • uv run --with pytest-cov pytest --cov=flexmeasures_mcp --cov-report=term-missing — 95% coverage
  • uv run pytest -m e2e — 2 passed against the Docker Compose stack

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants