malaria-forecast-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@malaria-forecast-mcpGive me an outbreak briefing for Luanda and Benguela"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
malaria-forecast-mcp
An MCP server that gives an AI agent access to provincial malaria surveillance and short-horizon outbreak forecasting for Angola — with the guardrails that make model output safe for an agent to act on.
Built by Joaquim Timóteo. The forecasting work it wraps is described in Operational Malaria Forecasting in Angola Using Ensemble Models, Regional Clusters, and Epidemiological Memory Features (ResearchGate, Feb 2026).
Why MCP instead of a REST API
A REST endpoint gives a model a URL and hopes the prompt explains the rest. MCP ships the contract alongside the capability, and three consequences follow that matter for anything forecasting-shaped:
Discovery is dynamic. Tool schemas are read at connect time. Adding compare_provinces made it available to every connected client without a single prompt being rewritten.
Provenance travels with the capability. malaria://model-card is a resource the model can read before quoting a number — validation method, measured skill, known failure modes. With a REST API that context lives in a PDF somewhere, which is to say it does not reach the model at all.
Refusals are structured. Ask for a 20-week horizon and you get a typed error naming the validated range, not a plausible-looking wrong number:
{
"error": "horizon_out_of_range",
"detail": "horizon_weeks must be between 1 and 8; got 20. The model was validated only to 8 weeks and will not extrapolate beyond it.",
"max_validated_horizon_weeks": 8
}That last one is the whole argument. A forecasting model wired to an agent without guardrails will answer any question it is asked, including the ones it has no business answering.
Related MCP server: CzechMedMCP
What it exposes
Tools
Tool | Purpose |
| All 18 provinces with epidemiological stratum (K-means burden clustering) |
| Weekly incidence and the rainfall driver, filtered by date range |
| 1–8 week forecast with empirical 80% intervals |
| Weeks running above the same-calendar-week seasonal baseline |
| Ranked forecast across provinces, for resource prioritisation |
Resources
malaria://model-card— architecture, validation method, measured metrics, limitations, guardrailsmalaria://provinces— province directory for grounding
Prompts
outbreak_briefing— walks the agent through model card → history → signals → forecast, then writes a briefing that always states intervals rather than point estimatescompare_and_prioritise— ranks provinces and requires the agent to say when two are not meaningfully separable
Guardrails
Horizons outside 1–8 weeks are refused, with the reason, rather than extrapolated.
Provinces with under 52 weeks of history are refused rather than forecast on a season the model has never seen.
Every point carries an empirical 80% interval from rolling-origin residuals — no distributional assumption.
Anomaly flags are seasonal. A flag means "high for this week of the year" against prior years, not "high in absolute terms" — which in a seasonal disease is the difference between a signal and a calendar.
Evaluation
The harness was written before the tools, and it earns its place: it caught a real defect.
python evals/backtest.pyRolling-origin backtest, 26 origins per province per horizon — 468 scored forecasts at each horizon:
h origins MAE baseline skill cov80
--------------------------------------------------
1 468 0.5677 0.8666 0.3450 79.70%
2 468 0.5992 0.8666 0.3085 80.13%
3 468 0.6137 0.8666 0.2919 80.77%
4 468 0.6100 0.8666 0.2961 82.69%
5 468 0.6051 0.8666 0.3018 82.69%
6 468 0.6299 0.8666 0.2732 85.26%
7 468 0.6461 0.8666 0.2544 86.11%
8 468 0.6538 0.8666 0.2456 86.11%skill is 1 − (model MAE / seasonal-naive MAE). The script exits non-zero if any horizon stops beating the baseline, so this is a gate rather than a report.
Two findings worth stating plainly, because they are the reason the harness exists:
Fixed ensemble weights lost to the baseline at 7–8 weeks. Local trend and climate signal decay with range while seasonal structure survives. Weights are now horizon-dependent, and skill is positive across the full range. Intuition said the ensemble was fine; the backtest said otherwise.
The intervals were miscalibrated. The textbook 0.80 quantile of absolute residuals produced 90–95% measured coverage — too wide, because residuals estimated on recent origins are systematically harder than the weeks being forecast. The quantile was calibrated down to 0.60, which measures at ~80% at short horizons and stays conservative (~86%) at long ones. Coverage is reported on every run so it cannot drift silently.
Data
The bundled dataset is synthetic. Provincial surveillance records are not redistributable, so the series reproduces the statistical shape of the real thing — rainy-season seasonality, burden strata, interannual variability, outbreak excursions — without exposing restricted data.
Every metric in this README describes this reimplementation on synthetic data. The published research model reports R² 0.985, MAE 6.9 per 1,000 and an 87.5% skill score on real surveillance across all 18 provinces, 2000–2024. Those are different numbers about a different artefact and the model card keeps them clearly separated.
To run against real data, implement the SurveillanceStore interface in data.py. No tool signature changes.
Install and run
git clone https://github.com/joaquimtimoteo/malaria-forecast-mcp
cd malaria-forecast-mcp
pip install -e .
python -m malaria_forecast_mcp # stdio server
python scripts/smoke_check.py # 26 end-to-end protocol checks
python evals/backtest.py # evaluation gate
pytest tests/ # full suiteClaude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"malaria-forecast": {
"command": "python",
"args": ["-m", "malaria_forecast_mcp"],
"env": { "PYTHONPATH": "/absolute/path/to/malaria-forecast-mcp/src" }
}
}
}Then ask: "Which three provinces should we prioritise six weeks out, and how confident are you?" — the agent reads the model card, ranks provinces, checks each against seasonal baselines, and reports intervals rather than point estimates.
Layout
src/malaria_forecast_mcp/
server.py MCP tools, resources, prompts
forecasting.py ensemble, intervals, guardrails
data.py surveillance store + synthetic generator
model_card.py machine-readable provenance
evals/backtest.py rolling-origin evaluation gate
scripts/smoke_check.py
tests/Roadmap
RAG over published epidemiological literature, so briefings cite evidence
Real-data adapter for DHIS2 surveillance exports
Intervention-effect handling (bed-net campaigns, IRS rounds)
Licence
MIT
Available Tools
5 toolscompare_provincesA
Rank provinces by forecast incidence to support prioritisation.
Args: horizon_weeks: Horizon to compare on, 1 to 8. top_n: How many provinces to return, highest forecast first.
Use this to answer "where should we pre-position resources", then drill into
a single province with forecast_incidence and detect_outbreak_signals.
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | ||
| horizon_weeks | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, so the description carries the full burden. It clearly explains the ranking behavior (highest first), parameter ranges, and purpose. It doesn't explicitly mention non-mutating behavior, but the action is read-only by nature and the response format is handled by the output schema. Slightly more detail on edge cases could push to 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three brief sections: purpose, args, usage. No wasted words. Every sentence adds value, and the structure is easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with 2 optional parameters, an output schema exists, and the description provides usage context, parameter semantics, and downstream tools. Fully adequate for an AI agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has zero description coverage, but the description explains both parameters: horizon_weeks ('1 to 8') and top_n ('how many provinces to return, highest forecast first'). This fully compensates for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states 'Rank provinces by forecast incidence to support prioritisation' with a clear verb (Rank) and resource (provinces). It distinguishes itself from siblings like `forecast_incidence` by focusing on cross-province comparison for prioritization.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit use case ('where should we pre-position resources') and names follow-up tools (`forecast_incidence`, `detect_outbreak_signals`) to drill into a single province. This gives clear when-to-use and alternative context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
detect_outbreak_signalsA
Flag recent weeks running above the same-calendar-week seasonal baseline.
Args: province: Province name, case-insensitive. lookback_weeks: How many recent weeks to screen. Defaults to 12. sigma: Standard deviations above the seasonal baseline required to flag.
A flag means "high for this time of year", compared against the same week in prior years -- not merely "high in absolute terms".
| Name | Required | Description | Default |
|---|---|---|---|
| sigma | No | ||
| province | Yes | ||
| lookback_weeks | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It adds valuable context: a flag means 'high for this time of year' compared to prior years, not merely high in absolute terms. This is beyond what the name/schema convey. It does not mention side effects or edge cases, but the read-only analytical nature is implicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, followed by a compact, well-organized argument list, and ends with a single clarifying interpretation note. Every sentence contributes value with no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity, the presence of an output schema, and the absence of annotations, the description covers the essential aspects: purpose, parameter meanings, and the seasonal baseline nuance. It does not mention usage alternatives or data limitations, but for a focused detection tool it is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must fully compensate. The 'Args' section adds meaningful semantics: province is case-insensitive, lookback_weeks specifies a default of 12, and sigma is explained as standard deviations above the baseline. This goes well beyond the raw schema properties.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource statement: 'Flag recent weeks running above the same-calendar-week seasonal baseline.' This clearly distinguishes the tool from siblings like compare_provinces, list_provinces, get_incidence_history, and forecast_incidence by focusing on seasonal anomaly detection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies a usage context (detecting outbreak signals via seasonal comparison) but provides no explicit when-to-use/when-not-to-use guidance or alternatives. Sibling tools are not referenced, so an agent would rely on the purpose statement alone to infer when to apply it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forecast_incidenceA
Forecast weekly malaria incidence 1-8 weeks ahead, with 80% intervals.
Args: province: Province name, case-insensitive. horizon_weeks: Forecast horizon, 1 to 8. Horizons beyond the validated range are refused rather than extrapolated.
Every point carries an empirical 80% interval derived from rolling-origin
backtest residuals. Read malaria://model-card for validation details and
known failure modes before acting on these numbers.
| Name | Required | Description | Default |
|---|---|---|---|
| province | Yes | ||
| horizon_weeks | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses the empirical 80% interval methodology (rolling-origin backtest residuals), explains that out-of-range horizons are refused rather than extrapolated, mentions case-insensitivity for province input, and directs users to the model-card for known failure modes. This is rich, transparent behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded with the core purpose and confidence intervals. Every sentence adds value: the Args section is directly relevant, and the reference to the model-card is a valuable safety note without padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate complexity (forecast, uncertainty, validation) and the presence of an output schema, the description covers all essential aspects: what, how far ahead, uncertainty interpretation, validation constraints, and a reference for caveats. The output schema handles return value details, so no further description is needed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides no property descriptions (0% coverage), but the description's 'Args' section adds crucial meaning: province is case-insensitive, and horizon_weeks must be 1-8 with refusal beyond that range. It also clarifies the default isn't stated but appears in schema. The description fully compensates for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Forecast') with a specific resource ('weekly malaria incidence') and clear scope ('1-8 weeks ahead, with 80% intervals'). This clearly distinguishes it from sibling tools that compare, list, retrieve history, or detect signals.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly indicates when to use the tool (for forecasting future incidence) and provides the important context that horizons beyond the validated range are refused. It references the model-card for validation details and failure modes, which is useful guidance, but it does not explicitly name alternative tools or state 'when not to use' beyond the horizon restriction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_incidence_historyA
Return weekly malaria incidence history for one province.
Args: province: Province name, case-insensitive (e.g. "Luanda", "moxico"). start_week: Optional ISO date (YYYY-MM-DD) lower bound. end_week: Optional ISO date (YYYY-MM-DD) upper bound. max_weeks: Cap on returned rows, most recent first. Defaults to 52.
Returns incidence per 1,000 population and the rainfall driver per week.
| Name | Required | Description | Default |
|---|---|---|---|
| end_week | No | ||
| province | Yes | ||
| max_weeks | No | ||
| start_week | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full disclosure burden. It discloses case-insensitive province matching, optional date bounds, max_weeks cap with most-recent-first ordering, and the returned metrics (incidence per 1,000 and rainfall driver). This is useful behavioral context beyond the schema, though it doesn't address error handling or side effects, which are minimal for a read-only history query.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured with an Args section and Returns statement. Every sentence adds value, and there is no filler or repetition. It is appropriately sized for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not detail return structures, but it still provides high-level return context. Parameter semantics and scope are adequately covered. A minor gap is the interaction between max_weeks and the date bounds, but this is not critical for a basic query tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must explain each parameter. It does so fully: province with examples and case-insensitivity, start_week and end_week as ISO date bounds, and max_weeks as a cap with default and ordering. This adds significant meaning beyond the bare schema types and titles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Return weekly malaria incidence history for one province.' This clearly specifies the tool's function and distinguishes it from siblings like compare_provinces, forecast_incidence, and list_provinces. The scope 'one province' also differentiates it from multi-province tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies when to use this tool by stating 'for one province' and focusing on historical incidence. It doesn't explicitly name alternatives or exclusions, but the context is clear: this is for fetching history for a single province, not for comparison, forecasting, or outbreak detection. This is clear context without explicit when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_provincesA
List Angolan provinces under surveillance with their epidemiological stratum.
Strata come from K-means clustering of historical burden: 'high', 'moderate' or 'low'. Use this first to resolve province names before calling other tools.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It explains that strata are derived from K-means clustering of historical burden and enumerates the possible values ('high', 'moderate', 'low'). This adds meaningful context about the data source and semantics. It doesn't mention side effects, but this is a simple list operation with likely no side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is exceptionally concise: two sentences. The first states the primary purpose, the second explains the strata and provides usage guidance. Every word earns its place, with no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter listing tool with an output schema, the description is complete. It specifies the scope (Angolan provinces under surveillance), the output (epidemiological stratum), the meaning of the stratum values, and the recommended usage order. Nothing crucial is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no parameters (0 params, 100% coverage vacuously). The baseline for 0 params is 4. The description adds no parameter information, but none is needed. It does clarify the meaning of the output values, which is more relevant here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'List Angolan provinces under surveillance with their epidemiological stratum.' This uses a specific verb (list) and resource (Angolan provinces), and distinguishes it from sibling tools that compare, retrieve history, forecast, or detect outbreaks. The scope is well-defined.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells when to use the tool: 'Use this first to resolve province names before calling other tools.' This gives strong positioning as a prerequisite, though it does not explicitly name alternatives or exclusions for other tools. Clear context but no explicit when-not-to-use comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a clearly distinct purpose: listing provinces, fetching historical incidence, forecasting, detecting outbreak signals, and comparing provinces. No overlap in functionality.
All tool names follow a consistent verb_noun snake_case pattern (list_, get_, forecast_, detect_, compare_).
Five tools perfectly cover the core workflow (list, historical, forecast, detect, compare) without bloat or missing essentials.
The set covers the full forecasting workflow: resolve province names, fetch history, forecast, detect anomalies, and rank provinces for prioritization. No obvious dead ends.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
MCP server connecting AI agents to non-custodial staking data across 130+ networks.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA unified MCP server providing observability, safety control, and behavior evolution for high-agency AI agents through tracing, replaying, and auditing. It features real-time firewall guardrails and ML-driven anomaly detection to monitor, block, or fork agent actions based on risk.7
- AlicenseNot gradedqualityDmaintenanceAn MCP server with 60 tools connecting AI assistants to Czech healthcare databases (SUKL, MKN-10, NRPZS) and global biomedical sources (PubMed, ClinicalTrials.gov, OpenFDA).1MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enforces runtime governance on AI agent actions — file access, command execution, delegation chains, and permission escalation.MIT
- AlicenseNot gradedqualityBmaintenanceMCP server enabling AI agents to enforce corrected rules as durable pre-output checks, manage processed memory, and query a temporal knowledge graph.Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/joaquimtimoteo/MCP-server-Malaria'
If you have feedback or need assistance with the MCP directory API, please join our Discord server