Credit Risk MCP Server
Click on "Deploy 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., "@Credit Risk MCP ServerScore a borrower earning $60k who wants a $300k loan and explain the top risk factors."
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.
Credit Risk MCP Server
An MCP (Model Context Protocol) server that exposes a trained Home Credit Default Risk model as tools any Claude client can call in plain conversation — score a borrower, explain the prediction with SHAP, compare applicants, and query the model's metadata.
It wraps the XGBoost model from my home-credit-default project and serves it two ways: locally over stdio (for Claude Desktop / Claude Code) and remotely over HTTP with API-key authentication (so any MCP client can reach it).
⚠️ Educational project. The model is trained on a public Kaggle dataset and is not a real lending-decision system. Do not use it to make credit decisions about real people.
What it does
Describe a loan applicant in plain terms and Claude will call the right tool:
Tool | What it returns |
| Default probability (0–1), a risk tier, and a decision flag at the recall-oriented 0.15 threshold |
| The top factors pushing risk up or down for one applicant, via SHAP, with human-readable names |
| Model type, AUC, precision/recall at different thresholds, and limitations |
| The model's globally most important features (mean |SHAP|) |
| Several applicants scored and ranked from most to least risky |
The interesting engineering problem: the model expects a 235-column encoded vector, but a person can only describe ~10 things about a borrower. The server starts from training-set medians and overlays the fields the user actually provides — replicating the notebook's exact encodings and engineered features — so a handful of plain inputs become a valid model row. It also reports which fields fell back to defaults, so the estimate's confidence stays transparent.
Related MCP server: AWS Resources MCP Server
Architecture
flowchart LR
Client["Claude client<br/>(Desktop / Code / any MCP client)"] -->|stdio or HTTP+Bearer| Server
subgraph Server["MCP server (FastMCP)"]
Tools["tool layer<br/>server.py"] --> Service["model_service.py<br/>build_feature_vector · score · explain"]
end
Service --> Artifacts["artifacts/<br/>model.json · feature columns · medians · SHAP importance"]The model and its supporting data are exported once into small, portable JSON
artifacts (artifacts/), so the server has no dependency on the original 362 MB
training CSV at run time.
Quickstart (local)
Requires uv.
uv sync
uv run --extra dev pytest -q # 24 tests
uv run python -m credit_risk_mcp.server # runs over stdio (waits for a client)See Connecting an MCP client below to wire it into Claude or any other MCP-capable app.
Remote (HTTP + auth)
Over HTTP the server requires a bearer key on every request, so it's safe to expose. Set the secret and run:
export CREDIT_RISK_API_KEY="$(uv run python -c 'import secrets; print(secrets.token_urlsafe(32))')"
uv run credit-risk-httpThe MCP endpoint is served at /mcp; a public /health route is left open for
platform health checks. Requests without a valid Authorization: Bearer <key>
header get 401. A Dockerfile and render.yaml are included for one-click
deployment to Render (or any Docker host): the platform injects $PORT and you
provide CREDIT_RISK_API_KEY as a secret. MCP_ALLOWED_HOSTS (comma-separated)
optionally restricts which Host headers are accepted; by default any host is
allowed and the bearer key is the sole gate.
Connecting an MCP client
The server speaks the standard MCP protocol, so any MCP-capable client can use
it. You need the /mcp URL and the API key. In the examples below, replace
YOUR-APP with your deployment's host and YOUR_KEY with its
CREDIT_RISK_API_KEY (deploy your own with the render.yaml above to get a key
of your own).
Claude Code (CLI)
Remote server over HTTP:
claude mcp add --transport http credit-risk https://YOUR-APP.onrender.com/mcp --header "Authorization: Bearer YOUR_KEY"…or run a local copy over stdio (no key needed):
claude mcp add credit-risk -s user -- uv --directory /ABSOLUTE/PATH/TO/credit-risk-mcp run python -m credit_risk_mcp.serverThen claude mcp list should show it connected. Start a new session and ask:
"Using credit-risk, score a borrower earning $60k who wants a $300k loan, and
explain the top factors."
Claude Desktop (and other stdio-only clients)
Bridge the remote server with mcp-remote.
In Claude Desktop, open Settings → Developer → Edit Config and add:
{
"mcpServers": {
"credit-risk": {
"command": "npx",
"args": [
"mcp-remote",
"https://YOUR-APP.onrender.com/mcp",
"--header",
"Authorization: Bearer YOUR_KEY"
]
}
}
}Fully restart Claude Desktop; the tools appear behind the tools/plug icon.
Any other MCP client
Point it at the Streamable HTTP endpoint https://YOUR-APP.onrender.com/mcp and
send Authorization: Bearer YOUR_KEY with each request. Clients that support
only stdio can use the mcp-remote bridge shown above.
Inspect the tools directly
# remote: run the Inspector, then choose "Streamable HTTP", enter the /mcp URL,
# and add an "Authorization: Bearer YOUR_KEY" header
npx @modelcontextprotocol/inspector
# local stdio:
npx @modelcontextprotocol/inspector uv run python -m credit_risk_mcp.serverNote: free hosting tiers sleep when idle, so the first request after a pause can take 30–60 s to wake the server.
About the model
Model: XGBoost classifier (100 trees, max depth 5), 235 features, trained on ~308k applications from the Kaggle Home Credit Default Risk dataset (SMOTE-balanced for the ~92%/8% class imbalance).
Performance: AUC-ROC ≈ 0.75.
Threshold: predictions use a 0.15 decision threshold rather than 0.5. In credit risk a missed defaulter (lost principal) costs far more than a false alarm, so the model is tuned for recall (~0.47 recall / ~0.21 precision at 0.15).
What drives it: external credit-bureau scores (
EXT_SOURCE_1/2/3) dominate, followed by employment type and demographics.
Tech stack
Python · MCP Python SDK (FastMCP) · XGBoost · SHAP · pandas · Pydantic · Starlette/Uvicorn (HTTP) · Docker · uv.
Available Tools
5 toolscompare_borrowersA
Score several applicants at once and rank them from most to least risky.
Use this to compare a batch of borrowers side by side. Each profile is scored exactly like score_borrower.
Args: profiles: two or more applicants to compare.
Returns {"ranked": [...]} sorted by default_probability descending. Each entry has: rank (1 = riskiest), index (position in the input list), default_probability, and risk_tier.
Educational model — not real lending advice.
| Name | Required | Description | Default |
|---|---|---|---|
| profiles | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral burden, and it does disclose useful traits: output ordering by default_probability descending, the rank-1-equals-riskiest convention, and an educational-purpose disclaimer. However, it omits batch limits, error behavior (e.g. what happens with fewer than two profiles), and any performance/rate considerations, leaving meaningful gaps for a mutation-free but compute-heavy batch tool.
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?
Front-loads the core action in the first sentence, then usage, then args, then return shape – a clean and scannable structure. It is slightly padded (the side-by-side sentence and the return breakdown partially overlap with the output schema), but nothing is genuinely wasted.
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?
An output schema exists, so the description need not explain return values, yet it does briefly, which is helpful redundancy rather than a gap. Combined with the clear arg definition and routing to score_borrower, an agent has enough to invoke it correctly; only edge-case behavior is unaddressed.
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?
Top-level schema description coverage is 0% for the 'profiles' parameter, so the description must compensate, and it does by defining it as 'two or more applicants to compare' – a cardinality constraint the schema does not enforce. The heavily documented nested BorrowerProfile fields carry the rest, so the description adds the one missing semantic without needing to restate the rest.
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?
States a specific verb and resource ('score several applicants at once and rank them from most to least risky') and explicitly names its relationship to the sibling score_borrower ('Each profile is scored exactly like score_borrower'). An agent can distinguish this batch tool from the single-borrower scorer without opening either schema.
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?
'Use this to compare a batch of borrowers side by side' clearly frames the use case, and the reference to score_borrower tells the agent this is the multi-applicant counterpart. It lacks an explicit when-not clause or a routing rule for when a single score_borrower call is preferable, so it stops short of full guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_predictionA
Explain a default-risk prediction: which factors push risk up or down.
Use this when the user wants the "why" behind a score, not just the number. Runs SHAP on the single applicant and returns the strongest contributing features with human-readable names.
Args: profile: the applicant to explain. top_n: how many contributing factors to return (default 8).
Returns a dict with default_probability, risk_tier, and top_factors — a list of {feature, friendly_name, value, shap_contribution, direction} ordered by impact, where direction is "increases risk" or "decreases risk".
Educational model — not real lending advice.
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | ||
| profile | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does so well: it discloses the method (SHAP), the scope (single applicant), and the shape of the output including the 'direction' semantics. It omits operational traits like whether it is read-only/side-effect-free, but the computation-only nature is strongly implied.
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 purpose and usage, then structured into Args and Returns. The Returns block partly duplicates the existing output schema, which is mild redundancy, but every other sentence earns its place.
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 two-parameter tool with an output schema, the description supplies purpose, usage guidance, parameter meaning, and a brief note on return contents. It is essentially complete, with only the detailed return schema left to the structured output definition as intended.
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?
Top-level schema description coverage is 0%, so the description must compensate, and it does: 'profile: the applicant to explain' and 'top_n: how many contributing factors to return (default 8)' cover both parameters, and the nested profile fields are documented in the schema itself.
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 verb and resource — 'Explain a default-risk prediction: which factors push risk up or down' — and frames it against the sibling that returns only a number. An agent can tell it apart from score_borrower and get_feature_importance without opening a schema.
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?
It gives a clear selection condition: 'Use this when the user wants the "why" behind a score, not just the number,' which routes the agent away from the scoring tool. It does not explicitly name or distinguish against get_feature_importance or compare_borrowers, so the routing guidance is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_feature_importanceA
Return the model's globally most important features (by mean |SHAP|).
Use this for "what drives this model overall?" questions, as opposed to the reasons behind one borrower's score. Returns {"top_features": [...]} ranked by average absolute SHAP impact across a sample, each entry carrying its raw name, a friendly name, and its importance score.
Args: top_n: how many features to return (default 10).
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the ranking metric (mean |SHAP|), that scores are averaged over a sample rather than a single prediction, and the per-entry payload (raw name, friendly name, importance score). It does not mention permissions, rate limits, or whether the sample is configurable, but for a read-only ranking tool the substantive behavioral context is present.
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?
Front-loads the core purpose, then the disambiguation, then the return shape, then the arg — a clean information hierarchy with no filler. Every clause earns its place and the Args block is conventional and scannable.
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?
An output schema exists, so the return contract need not be re-explained, yet the description still summarizes it usefully; the single optional parameter is documented and the sibling distinction is drawn. Nothing an agent needs in order to select and call this tool 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?
Schema coverage is 0% and the schema carries only a default with no description, so the description must compensate, and it does: 'top_n: how many features to return (default 10)' explains both the meaning and the fallback behavior. It is complete for the single parameter, though it adds no guidance on sensible ranges or interaction with the underlying sample.
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?
States a specific verb and resource ('Return the model's globally most important features') and immediately scopes it with the SHAP methodology. It explicitly distinguishes itself from the sibling concern of per-borrower explanations ('as opposed to the reasons behind one borrower's score'), so an agent can route correctly without opening other schemas.
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?
Gives an explicit when-to-use heuristic ('what drives this model overall? questions') paired with the contrasting case ('the reasons behind one borrower's score'), which maps directly onto the sibling explain_prediction. The routing decision is fully spelled out rather than left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_model_infoA
Describe the model itself: type, performance, and limitations.
Use this to answer questions about how good the model is or how it should be used — no borrower needed. Returns model type, feature count, training size, AUC-ROC, precision/recall at the 0.50 and 0.15 thresholds, the recommended threshold, and an honest limitations note (educational, not real lending advice).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the exact returned quantities (type, feature count, training size, AUC-ROC, precision/recall, recommended threshold) and flags an 'honest limitations note' plus an educational-not-lending-advice caveat. It does not explicitly state that the call is read-only/auth-free, which is the only meaningful gap.
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?
Purpose and usage guidance are front-loaded in the first two sentences, followed by a single enumeration of outputs. The output enumeration is somewhat redundant given an output schema exists, but it is compact and earns its place by adding interpretation context.
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, annotated-free read tool with an output schema, the description covers purpose, usage, and expected return content. The only under-covered aspect is the explicit absence of side effects or auth requirements, which is minor for an information-lookup 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?
The tool takes zero parameters, so there is nothing for the description to disambiguate. The baseline for a parameterless tool applies, and the description correctly adds no misleading parameter detail.
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?
States a specific verb and resource ('Describe the model itself') and immediately scopes it away from borrower-specific siblings with 'no borrower needed.' An agent can distinguish this from score_borrower, explain_prediction, and compare_borrowers without opening any schema.
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?
Gives a clear trigger — 'questions about how good the model is or how it should be used' — and an implicit exclusion ('no borrower needed') that separates it from borrower-focused siblings. It stops short of naming those sibling tools as alternatives, which keeps it from a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
score_borrowerA
Estimate a loan applicant's probability of default.
Use this to get a single risk number for one borrower. Describe the applicant in plain terms — only annual income and loan amount are required; every other field falls back to the population median when omitted.
Returns a dict with:
default_probability: estimated probability of default (0-1)
risk_tier: "low" / "moderate" / "elevated" / "high"
flag_default: True if the probability is at or above the 0.15 decision threshold (this model is tuned for recall, not a 50% cutoff)
threshold_used: the decision threshold (0.15)
fields_defaulted: which optional fields fell back to medians
Educational model trained on a Kaggle dataset — not real lending advice.
| Name | Required | Description | Default |
|---|---|---|---|
| profile | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present the description carries the full burden and does so well: it discloses the median-fallback behavior for omitted fields, the non-standard 0.15 decision threshold, the recall-tuned flagging semantics, and the educational/non-advisory limitation. These are exactly the traits an agent needs before trusting the output.
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?
Front-loaded purpose followed by scoping, a field-defaulting note, and a compact bulleted return contract — every section is useful. The return-value bullets are somewhat longer than necessary given a dedicated output schema exists, keeping it just under a 5.
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 one-parameter scoring tool with an output schema, the description covers purpose, scoping, input semantics, threshold behavior, and limitations, leaving no material gap for correct invocation or interpretation.
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 reported at 0% (the top-level 'profile' parameter has no description), so the description has to compensate. It does: it states that only annual income and loan amount are required and that every other field falls back to the population median, which is the key semantic an agent needs when populating a sparse profile.
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?
States a specific verb+resource (estimate probability of default) and scopes it to a single applicant, which cleanly separates it from compare_borrowers. An agent can identify the tool's job without opening the schema.
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?
'Use this to get a single risk number for one borrower' gives clear context for selection and implicitly routes multi-borrower cases elsewhere. It does not explicitly name or exclude sibling alternatives such as compare_borrowers or explain_prediction, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
compare_borrowers - First observed
explain_prediction - First observed
get_feature_importance - First observed
get_model_info - First observed
score_borrower
TDQS
Scored across 5 tools
Each tool targets a distinct purpose: score_borrower (single), compare_borrowers (batch ranking), explain_prediction (local SHAP), get_feature_importance (global SHAP), and get_model_info (metadata). The descriptions explicitly contrast overlapping-sounding pairs like global feature importance vs per-borrower explanation, leaving no realistic selection ambiguity.
All five names follow a clean verb_noun snake_case pattern (get_feature_importance, compare_borrowers, get_model_info, score_borrower, explain_prediction). The verbs are apt and used consistently with no mixing of conventions.
Five tools is a well-scoped set for a model-inference domain, with each tool earning a distinct role (score, compare, explain, global importance, metadata). Nothing is redundant or missing for the apparent purpose.
The surface fully covers the inference lifecycle: single scoring, batch comparison, per-prediction explanation, global feature importance, and model metadata/limitations. As a stateless scoring service there are no CRUD gaps, and the tools form a coherent complete workflow.
Related MCP Connectors
Build and manage AI-native customer support agents from Claude or any MCP client.
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
- QuallaaOAuthcom.quallaa
Talk to your public-facing AI from any MCP client — Claude, ChatGPT, Cursor, Cline, Windsurf.
AI-powered corporate learning platform — manage courses, users, and insights via Claude.
Related MCP Servers
- FlicenseAqualityDmaintenanceThe server facilitates natural language interactions for exploring and understanding codebases, providing insights into data models and system architecture using a cost-effective, simple setup with support for existing Claude Pro subscriptions.427-
- AlicenseBqualityDmaintenanceA Model Context Protocol server that enables Claude to execute Python code using boto3 to query and manage AWS resources directly from conversations.124MIT
- AlicenseNot gradedqualityFmaintenanceA modular server implementation for Claude AI assistants with integrated tools, enabling Claude to perform actions and access external resources like file systems, web searches, browser automation, financial data, and document generation.107MIT
- AlicenseNot gradedqualityDmaintenanceTurns any CLI tool or REST API into an MCP server for Claude, enabling Claude to use git, databases, or any API through natural language.MIT