Andalusia AI MCP Server
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., "@Andalusia AI MCP ServerWhy did readmission rates spike in March?"
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.
Andalusia AI MCP Server
This MCP server exposes six Andalusia AI hospital metric tools to Claude:
resolve_entitiessearch_membersquery_cubeget_measure_definitionresolve_why_questionexecute_investigation
It is a thin wrapper around two FastAPI services:
Librarian:
http://197.164.100.18:18080Tools:
http://197.164.100.18:28081Investigator:
http://197.164.100.18:28082
This repository itself is not Dockerized. In production, this MCP service runs as a Node.js process under systemd. The Andalusia backend services it calls may run separately in Docker on the same server. For example, on the current host:
MCP service systemd: andalusia-ai-mcp.service
Librarian backend Docker: librarian-resolver-1
Tools backend Docker: claude_project-tools-1
Librarian vector database Docker: librarian-qdrant-1When debugging a tool failure, check both MCP logs and the relevant backend container logs.
Backend calls use the shared X-Librarian-Secret header. Keep the real secret in .env; do not commit it.
Non-secret app settings live in config.yml.
Tool descriptions live in tool-descriptions.yml.
Project Layout
config.yml Non-secret runtime settings
.env Secrets only
tool-descriptions.yml Editable Claude-facing tool guidance
src/config.ts Loads config.yml plus env overrides
src/toolDescriptions.ts Loads tool-descriptions.yml
src/andalusiaClient.ts Backend API client
src/mcpServer.ts Creates the MCP server and registers tools
src/tools/index.ts Tool registry: controls which tools are enabled
src/tools/*.ts One file per MCP toolRelated MCP server: FHIR MCP Server
Setup
npm install
cp config.example.yml config.yml
cp .env.example .env
npm run buildEdit config.yml for non-secret settings:
andalusiaLibrarianBaseUrl: http://197.164.100.18:18080
andalusiaToolsBaseUrl: http://197.164.100.18:28081
andalusiaInvestigatorBaseUrl: http://197.164.100.18:28082
andalusiaRequestTimeoutMs: 100000
andalusiaInvestigatorRequestTimeoutMs: 500000
monitoringEventLogFile: /var/log/andalusia-ai-mcp/monitoring-events.jsonl
monitoringEventLogMaxBytes: 52428800
monitoringEventLogReplayMaxBytes: 10485760
monitoringEventLogReplayMaxEvents: 10000
monitoringEventLogReplayMaxAgeMs: 86400000
monitoringMaxMetricBuckets: 200
oauthStateFile: /var/lib/andalusia-ai-mcp/oauth-state.json
oauthMaxClients: 1000
oauthMaxAuthorizationCodes: 1000
oauthMaxAccessTokens: 5000
oauthMaxRefreshTokens: 5000Edit .env for secrets:
ANDALUSIA_LIBRARIAN_SECRET=your-shared-secretEnvironment variables still override config.yml, which is useful for one-off
local runs and deployment systems.
Adding Tools
Each MCP tool lives in its own file under src/tools/ and implements the
AndalusiaTool interface from src/tools/types.ts.
To add a tool:
Add the backend method to
src/andalusiaClient.ts.Add a new
src/tools/<toolName>.tsfile with itsname,title,descriptionKey,inputSchema, andhandler.Add the tool factory to
src/tools/index.ts. This is the registry that decides which tools the MCP server exposes.Add matching editable guidance to
tool-descriptions.yml.
Example registry entry:
export function createAndalusiaTools(context: ToolContext): AnyAndalusiaTool[] {
return [
createResolveEntitiesTool(context),
createSearchMembersTool(context),
createQueryCubeTool(context),
createGetMeasureDefinitionTool(context),
createResolveWhyQuestionTool(context),
createExecuteInvestigationTool(context)
];
}If a tool is not added to src/tools/index.ts, it will not be registered with
the MCP server even if its file exists.
Guides
HTTP Mode
MCP_TRANSPORT=http MCP_HTTP_PORT=3000 npm startThen connect Claude with Streamable HTTP:
claude mcp add --transport http andalusia-ai http://127.0.0.1:3000/mcpFor hosted Claude connector usage, set MCP_PUBLIC_URL to the public /mcp
URL and set MCP_HTTP_BEARER_TOKEN. Claude discovers OAuth metadata, registers
dynamically, and prompts for that token as the connector code during sign-in.
Production Monitoring Dashboard
HTTP mode exposes built-in production monitoring endpoints:
Production dashboard:
https://ai-mcp.andalusiagroup.net/dashboard/dashboard- human-facing browser UI for production monitoring. Open this page to inspect MCP usage, tool calls, latency, failures, uptime, memory, backend configuration, JSON-RPC methods, and recent errors./dashboard/metrics- JSON API used by the dashboard. Use this endpoint for debugging, scripts, smoke tests, or custom internal tools that need the full structured monitoring snapshot./metrics- Prometheus-compatible text endpoint. Use this endpoint as the scrape target for Prometheus, Grafana, Datadog agents, or other monitoring systems./ready- readiness check for required Andalusia backend configuration.
Quick reference:
/dashboard Browser UI for humans
/dashboard/metrics JSON monitoring snapshot for the dashboard and scripts
/metrics Prometheus-compatible metrics for monitoring platforms
/ready Readiness check for deploy/load-balancer health gatesApplication logs are written to stdout/stderr and captured by systemd. Enable
persistent journald storage on the production host so journalctl logs survive
reboots:
sudo install -d -m 2755 -o root -g systemd-journal /var/log/journal
sudo systemctl restart systemd-journaldWhen MCP_HTTP_BEARER_TOKEN is configured, /dashboard/metrics and /metrics
require the same bearer token:
curl -H "Authorization: Bearer $MCP_HTTP_BEARER_TOKEN" \
https://ai-mcp.andalusiagroup.net/dashboard/metrics
curl -H "Authorization: Bearer $MCP_HTTP_BEARER_TOKEN" \
https://ai-mcp.andalusiagroup.net/metricsThe dashboard keeps bounded working counters in memory. On startup, it replays
recent bounded history from the JSONL event log, then continues with live
updates.
When monitoringEventLogFile is configured, each HTTP request, tool call, and
server error is also appended to a bounded JSONL event log. The file rotates to
.1 when it reaches monitoringEventLogMaxBytes.
The dashboard does not depend only on the current process runtime state. Runtime counters are used while the service is running, but after a restart the dashboard rebuilds recent monitoring results from the persistent JSONL event log on disk before continuing with live updates.
Read the live monitoring event log:
sudo tail -f /var/log/andalusia-ai-mcp/monitoring-events.jsonlRead recent monitoring events:
sudo tail -n 100 /var/log/andalusia-ai-mcp/monitoring-events.jsonlPretty-print recent JSONL events:
sudo tail -n 50 /var/log/andalusia-ai-mcp/monitoring-events.jsonl | jqRead the previous rotated monitoring log:
sudo tail -n 100 /var/log/andalusia-ai-mcp/monitoring-events.jsonl.1Read application stdout/stderr logs captured by systemd:
sudo journalctl -u andalusia-ai-mcp -n 200
sudo journalctl -u andalusia-ai-mcp -f
sudo journalctl -u andalusia-ai-mcp --since todayFor long-term retention and alerting, scrape /metrics with your monitoring
platform and alert on server errors, tool failures, high P95 latency, missing
readiness checks, and process restarts. Use the JSONL event log or journald for
forensics and recent dashboard replay after process restarts.
Update needed: add an explicit retention policy for filesystem logs. The MCP
monitoring event log currently rotates by size, not by age. For normal
operations, keep raw monitoring and journald logs for about 30 days unless a
compliance requirement says otherwise. A production logrotate policy can be
used for the JSONL file, for example:
/var/log/andalusia-ai-mcp/monitoring-events.jsonl {
daily
rotate 30
compress
missingok
notifempty
copytruncate
create 0640 ai ai
}Also configure journald retention on the host, for example with
MaxRetentionSec=30day in journald.conf if that matches the server policy.
OAuth clients, access tokens, and refresh tokens can be persisted with
oauthStateFile. The service still keeps bounded working maps in memory while
running, but the configured caps prevent unbounded growth and the state file
allows Claude connector sessions to survive process restarts.
Tool usage rows are driven by the MCP tool registry in src/tools/index.ts.
When a new tool is added to createAndalusiaTools, the dashboard automatically
includes it and starts its call count at 0 after the service restarts.
Troubleshooting Backend Failures
The MCP durable monitoring log shows MCP-level failures:
sudo jq -r 'select(.type=="tool_call" and .success==false) | [.ts, .toolName, .durationMs, .error] | @tsv' \
/var/log/andalusia-ai-mcp/monitoring-events.jsonlExample:
resolve_entities librarian POST /resolve_entities failed with HTTP 500That means the MCP service called the Librarian backend and the backend returned HTTP 500. To find the root cause, check the Librarian Docker logs:
docker logs librarian-resolver-1 2>&1 | rg -C 5 '402 Payment Required|openrouter.ai/api/v1/embeddings|HTTPStatusError'If Docker requires sudo:
sudo docker logs librarian-resolver-1 2>&1 | grep -C 5 "402 Payment Required"A known failure is:
httpx.HTTPStatusError: Client error '402 Payment Required'
for url 'https://openrouter.ai/api/v1/embeddings'This is not a Claude quota error. It means the Librarian backend's OpenRouter
embedding provider returned 402 Payment Required, usually because OpenRouter
billing/credits/API-key access needs attention.
Publish To Production
Run from the project directory on the production host:
cd /home/ai/Workspace/yasser/Claude_Mcp
npm run typecheck
npm run buildInstall the non-secret runtime files:
sudo install -d -m 750 -o root -g ai /etc/andalusia-ai-mcp
sudo install -d -m 750 -o ai -g ai /var/lib/andalusia-ai-mcp
sudo install -d -m 750 -o ai -g ai /var/log/andalusia-ai-mcp
sudo install -m 640 -o root -g ai config.yml /etc/andalusia-ai-mcp/config.yml
sudo install -m 640 -o root -g ai tool-descriptions.yml /etc/andalusia-ai-mcp/tool-descriptions.ymlDo not overwrite the production env file unless secrets changed. It should already contain:
MCP_HTTP_BEARER_TOKEN=your-connector-code
ANDALUSIA_LIBRARIAN_SECRET=your-shared-secretInstall service/proxy config and restart:
sudo cp deploy/andalusia-ai-mcp.service /etc/systemd/system/andalusia-ai-mcp.service
sudo cp deploy/andalusia-ai-mcp.nginx.conf /etc/nginx/conf.d/andalusia-ai-mcp.conf
sudo systemctl daemon-reload
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl reset-failed andalusia-ai-mcp
sudo systemctl restart andalusia-ai-mcp
sudo systemctl status andalusia-ai-mcp --no-pager -lVerify:
curl -sS http://127.0.0.1:3001/health
curl -i https://ai-mcp.andalusiagroup.net/health
curl -i https://ai-mcp.andalusiagroup.net/.well-known/oauth-authorization-serverExpected health response:
{"ok":true,"name":"andalusia-ai-mcp"}Public HTTPS
For https://ai-mcp.andalusiagroup.net/mcp, run the Node server privately on
127.0.0.1:3001 and let Nginx terminate TLS on port 443.
This repo is configured to use the existing *.andalusiagroup.net wildcard
certificate:
/etc/nginx/certs/fullchain.crt
/etc/nginx/certs/private.keyInstall the wildcard certificate and Nginx config on the server.
On this host, Docker already owns port 80, so the systemd Nginx config is
443-only and does not provide an HTTP-to-HTTPS redirect.
sudo dnf install -y nginx
command -v nginx
sudo systemctl enable --now nginx
sudo install -d -m 700 -o root -g root /etc/nginx/certs
sudo install -m 644 /path/to/wildcard/fullchain.crt /etc/nginx/certs/fullchain.crt
sudo install -m 600 /path/to/wildcard/private.key /etc/nginx/certs/private.key
sudo cp deploy/andalusia-ai-mcp.nginx.conf /etc/nginx/conf.d/andalusia-ai-mcp.conf
sudo nginx -t
sudo systemctl reload nginxIf command -v nginx prints nothing or nginx.service does not exist, Nginx is
not installed on the host. Install it first, then rerun the Nginx commands.
If install: cannot stat ... appears, replace /path/to/wildcard/... with the
real certificate and private key paths.
Files under /etc/pki/ca-trust/... are system CA bundles, not the
*.andalusiagroup.net server certificate or its private key.
If nginx fails with bind() to 0.0.0.0:80 failed and ss shows
docker-proxy, port 80 is already handled by a Docker container. In that
case, remove the package default listen 80 server from
/etc/nginx/nginx.conf and run systemd Nginx as a 443-only TLS proxy, or stop
the container before using systemd Nginx on both ports.
Verify locally and over HTTPS:
curl http://127.0.0.1:3001/health
curl -vk https://ai-mcp.andalusiagroup.net/mcpFor the full production checklist, including systemd and bearer-token setup, see Deploy on HTTPS 443.
This server cannot be installed
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
Read and write patients, facilities, medical documents, and consolidated FHIR records in Metriport.
HealthData.gov MCP — wraps HealthData.gov CKAN API (free, no auth)
Securely access and manage FHIR healthcare data stored in Medplum.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with a comprehensive healthcare management system through FastAPI, supporting operations for patients, doctors, appointments, medical records, telemedicine, lab orders, prescriptions, insurance claims, and more with JWT authentication.5MIT
- AlicenseAqualityCmaintenanceProvides seamless integration with FHIR APIs, enabling AI/LLM tools to search, retrieve, and analyze clinical healthcare data with support for SMART-on-FHIR authentication and multiple transport protocols.7134Apache 2.0
- FlicenseAqualityCmaintenanceEnables interaction with synthetic NIH-style clinical research data through tools for searching publications, querying patient metadata, analyzing AAA measurements, and retrieving protocol guidance.5
- AlicenseNot gradedqualityBmaintenanceExposes a FHIR endpoint as deterministic read-only tools, providing a context layer for retrieving clinical data from FHIR servers.MIT
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/yasserkh2/Claude_Mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server