MCP server · Org-owned · Audited from source

FastMCP MCP server

by jlowin/fastmcpApache-2.0 licenceAudited 20 Sep 2026 · source 9bfb2e369f85

PyPI fastmcpssestdiostreamable-http★ 27,766
✕BLOCKGrade F · 27/100 · 20 Sep 2026 · 9bfb2e3

Is it safe? No — BLOCK, grade F (27/100). It exposes 305 tools: 265 read, 37 write and 3 destructive. The audit recorded 80 findings (0 critical, 2 high, 16 medium, 57 low). Maintainer's description: 🚀 The fast, Pythonic way to build MCP servers and clients.

Ask an AI about this pageGChatGPTCClaudePPerplexityGeGeminiXGrok
More
Cite

Cite this page

ModelsAtlas. “FastMCP MCP server (jlowin/fastmcp)”. Retrieved 20 Sep 2026. https://modelsatlas.com/mcp/jlowin/fastmcp

Why this is BLOCK. The audit found 0 critical and 2 high findings; the most severe is Code injection at fastmcp_slim/fastmcp/server/providers/skills/_common.py:105. Each finding is listed below with its file and line.

Why this page is still public. People search for this server by name. Hiding it would leave them with the README's word alone; here they see what the code does. We list it so you can decide, and we do not show connect commands for BLOCK servers.

Trust audit

Audit 0.4.1 · full source read 20 Sep 2026

Trust score27/100✕BLOCK F
0 critical2 high16 medium57 low5 info

80 findings, listed below with the file and line each was found on. Grade A needs a sandboxed behavioural run too; this audit read the source only.

What the source does

  • FilesystemDeclared4 observations
  • NetworkDeclared2 observations
  • ShellDeclared5 observations
  • DependenciesNot pinnedSome ranges float
  • SecretsFoundSee the findings

Findings (80)

Sorted by severity · the 25 most severe of 80 are listed

HIGHCode injectioncode.deserialize · fastmcp_slim/fastmcp/server/providers/skills/_common.py:105
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
parsed = yaml.load(frontmatter_text, Loader=yaml.BaseLoader)
Why
deserialises untrusted bytes into live objects
Fix
use json or yaml.safe_load
HIGHPrompt injectionprompt.hide_from_user · docs/getting-started/upgrading/from-mcp-sdk-v2.mdx:87
F-01 Prompt injectionCWE-94 · CWE-1427Layer L2
FastMCP has no resolver injection, but the underlying requests survive in a different shape: on a modern connection `Elicit`, `Sample`, and `ListRoots` all ride the guard pattern, where the tool retur
Why
asks the agent to act without the user's knowledge
Fix
—
MEDIUMCode injectioncode.dynamic_import · fastmcp_slim/fastmcp/server/__init__.py:14
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
return importlib.import_module(f"fastmcp.server.{name}")
Why
No further detail recorded for this rule.
Fix
—
MEDIUMCode injectioncode.dynamic_import · fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py:197
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
return importlib.import_module(private_name)
Why
No further detail recorded for this rule.
Fix
—
MEDIUMCode injectioncode.dynamic_import · fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py:213
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
return importlib.import_module(module_name)
Why
No further detail recorded for this rule.
Fix
—
MEDIUMCode injectioncode.dynamic_import · fastmcp_slim/fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py:132
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
server_module = importlib.import_module(module_name)
Why
No further detail recorded for this rule.
Fix
—
MEDIUMHard-coded secretssecret.db_uri · examples/memory.py:40
F-03 Hard-coded secretsCWE-798 · CWE-321Layer L1

Excerpt withheld: it is a secret, and we never print one.

Why
No further detail recorded for this rule.
Fix
—
MEDIUMHard-coded secretssecret.db_uri · examples/memory.py:302
F-03 Hard-coded secretsCWE-798 · CWE-321Layer L1

Excerpt withheld: it is a secret, and we never print one.

Why
No further detail recorded for this rule.
Fix
—
MEDIUMHard-coded secretssecret.generic · tests/server/http/test_stale_access_token.py:60
F-03 Hard-coded secretsCWE-798 · CWE-321Layer L1

Excerpt withheld: it is a secret, and we never print one.

Why
No further detail recorded for this rule.
Fix
—
MEDIUMHard-coded secretssecret.generic · tests/server/http/test_stale_access_token.py:68
F-03 Hard-coded secretsCWE-798 · CWE-321Layer L1

Excerpt withheld: it is a secret, and we never print one.

Why
No further detail recorded for this rule.
Fix
—
MEDIUMHard-coded secretssecret.generic · tests/server/http/test_stale_access_token.py:206
F-03 Hard-coded secretsCWE-798 · CWE-321Layer L1

Excerpt withheld: it is a secret, and we never print one.

Why
No further detail recorded for this rule.
Fix
—
MEDIUMHard-coded secretssecret.private_key · tests/server/auth/test_jwt_provider.py:208
F-03 Hard-coded secretsCWE-798 · CWE-321Layer L1

Excerpt withheld: it is a secret, and we never print one.

Why
No further detail recorded for this rule.
Fix
—
MEDIUMFilesystem / pathmcp.destructive_tools
F-05 Filesystem / pathCWE-22 · CWE-59Layer L3
confirm_delete, delete_item, reset_user_password
Why
3 tool(s) can delete or overwrite
Fix
prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenanceinv.hidden_file · .ccignore
F-13 Inventory / provenanceCWE-1104Layer L0
.ccignore
Why
hidden member outside the usual dotfiles
Fix
review its purpose
LOWInventory / provenanceinv.hidden_file · .coderabbit.yaml
F-13 Inventory / provenanceCWE-1104Layer L0
.coderabbit.yaml
Why
hidden member outside the usual dotfiles
Fix
review its purpose
LOWInventory / provenanceinv.hidden_file · .pre-commit-config.yaml
F-13 Inventory / provenanceCWE-1104Layer L0
.pre-commit-config.yaml
Why
hidden member outside the usual dotfiles
Fix
review its purpose
LOWInventory / provenanceinv.hidden_file · docs/.ccignore
F-13 Inventory / provenanceCWE-1104Layer L0
.ccignore
Why
hidden member outside the usual dotfiles
Fix
review its purpose
LOWInventory / provenanceinv.hidden_file · examples/tasks/.envrc
F-13 Inventory / provenanceCWE-1104Layer L0
.envrc
Why
hidden member outside the usual dotfiles
Fix
review its purpose
LOWCode injectioncode.deserialize · .github/scripts/test-ci-workflows.mjs:20
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
print(json.dumps({name: yaml.load(Path(f'.github/workflows/{name}.yml').read_text(), Loader=yaml.BaseLoader)
Why
deserialises untrusted bytes into live objects
Fix
use json or yaml.safe_load
LOWCode injectioncode.deserialize · tests/utilities/json_schema_type/test_real_world_schemas.py:204
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
spec = yaml.load(spec_file.read_text(), Loader=CSafeLoader)
Why
deserialises untrusted bytes into live objects
Fix
use json or yaml.safe_load

Tools it exposes

305 declared in source · 3 destructive

265 read37 write3 destructive

3 tools can delete or overwrite. An agent that can be talked into calling a tool can be talked into calling this one, so give it a token scoped to what you need.

ToolWhat it doesRisk
confirm_deleteParks the task on one elicitation before doing the (pretend) deletion.destructive
delete_itemRemove an item by ID and return the remaining inventory.destructive
reset_user_passwordReset a userdestructive
_trigger_docketreturnwrite
addreturn a + bwrite
add_commentAdd a comment to a request. Returns the updated request.write
add_itemAdd a new item to inventory and return the full list.write
add_numbersAdd two numberswrite
bare_sync_accessheaders = get_http_headers()write
blockingimport timewrite
calculateAdd two numbers (v1.0).write
contact_formShow a form to create a new contact, with a live contact list below.write
context_sync_accessheaders = get_http_headers()write
coordinatedstarted.set()write
createCreate itemwrite
create_projectreturnwrite
create_userCreate a user.write
custom-addreturn x + ywrite
custom_savereturn namewrite
dynamic_addAdd two numbers with offsetwrite
execute_tradeExecute a trade (simulated).write
fast_sync_tooltime.sleep(0.01)write
modifyModify the data provided.write
query_syncassert connection.is_openwrite
return_setreturn {1, 2, 3}write
runRun somethingwrite
run_query...write
savereturn fwrite
save_contactSave a new contact and return the updated list.write
admin_toolreturnread
analyze_dataFilter and analyze sales data. Returns rows, summary, and chart data.read
analyze_portfolioAnalyze a portfolio of stock symbols.read
annotatecurrent = trace.get_current_span()read
api_healthShow health details for each API endpoint.read
approve_requestApprove a pending request and return updated lists.read
ask_nameresult = await ctx.elicit(read
async_echoAsync tool for testingread
async_toolAn async tool.read
background_toolreturn xread
bare_toolinfo = get_task_context()read
batch_processProcess batches.read
bg_progress_toolawait progress.set_total(3)read
bg_toolawait asyncio.sleep(0.01)read
blockedreturnread
book_flightreturn _ask(read
boomraise ValueError(read
calcreturnread
call_apireturn fread
capture_docket_iddocket_ids.append((call_num, id(docket)))read
chargeCharge a payment (v1.0 - basic).read
check_bothassert isinstance(docket, Docket)read
check_docketassert isinstance(docket, Docket)read
check_headersheaders = _worker_snapshot_headers()read
check_permissionreturn fread
check_request_headerreturn _worker_snapshot_headers().get(read
check_tokentoken = get_access_token()read
check_worker_statusreturn fread
checkpointif ctx.request_state is None:read
claimed_toolreturn Noneread
combinereturn fread
computeCompute something.read
countreturn 1read
crunch...read
customA custom toolread
custom_namereturn str(x)read
custom_toolA custom toolread
declared_statusreturn {read
demoA demo app that exercises various MCP message types.read
doublereturn n * 2read
dynamic_multiplyMultiply two numbersread
echoEcho a message back.read
echo_with_logsEcho a message and emit log notifications.read
employee_directoryShow a searchable, sortable employee directory.read
enabledTask enabledread
enter_envawait ctx.disable_components(tags={read
error_toolraise ToolError(read
excluded_versioned_toolreturnread
exit_envawait ctx.reset_visibility()read
explicit_toolreturn {read
explodesraise MCPError(code=INTERNAL_ERROR, message=read
freturn 42read
failAlways raises an error.read
failing_toolraise ValueError(read
farewellSay farewell in their language.read
fast_async_toolawait anyio.sleep(0.01)read
fast_toolreturn x * 2read
feature_flagsToggle feature flags with live preview.read
fetchFetch data fromread
fetch_datareturn (read
filter_by_categoryFilter inventory by category. Passread
filter_dataFilter sales data by region and/or product.read
finance_toolreturnread
forbiddenForbidden toolread
foreverawait asyncio.Event().wait()read
full_nameresponses = ctx.input_responsesread
get_auth_typeauth = headers.get(read
get_client_ipreturn request.client.host if request.client elseread
get_market_dataGet current market data for a symbol.read
get_my_emailsasync with httpx2.AsyncClient() as client:read
get_nodeGet a noderead
get_prGet a pull requestread
get_request_detailsGet full details for a single request. Available to both model and UI.read
get_request_idreturn ctx.request_idread
get_summaryReturn summary statistics for the full dataset.read
get_test_file_from_serverNo description in the sourceread
get_test_pdf_from_urlNo description in the sourceread
get_user_idreturn token.claims.get(read
get_weatherGet the current weatherread
greetGreet someone in their language.read
greet_userreturn fread
guardcalls.append(1)read
hidden_toolreturnread
included_versioned_toolreturnread
inforeturnread
inspect_itemsreturn {read
instant_timeoutawait anyio.sleep(0) # Give the event loop a chance to check timeoutread
internal_toolreturnread
introspectreturn fread
leakraise ValueError(read
list_contactsReturn all contacts. Visible to both the model and the UI.read
list_requestsList requests, optionally filtered by status.read
list_usersList all system users.read
log_progressctx.report_progress(50, 100,read
long_timeoutawait anyio.sleep(0.01)read
make_toolreturnread
mixed_audio_list_fnreturn [read
mixed_depsassert isinstance(ctx, Context)read
mixed_file_list_fnreturn [read
mixed_list_fnreturn [read
multi_inputParks the task on two elicitations at once, so they can be answered separately.read
multiplyreturn x * yread
my_functionreturn fread
my_task# Works transparently in both foreground and background task modesread
my_toolA toolread
mytoolreturnread
new_toolreturnread
no_task_toolreturnread
normal_toolreturn config[read
okreturnread
old_toolreturnread
onereturn 1read
one_questionresponses = ctx.input_responsesread
only_v5returnread
pickreturnread
pingPing the serverread
plan_dinnerPlan a dinner menu, asking the user what theyread
positional_nameNo description in the sourceread
premium_toolreturnread
private_toolreturn fread
process_datareturn fread
progress_toolawait ctx.report_progress(0, 100,read
project_overviewShow project details organized in tabs.read
protectedreturnread
protocol_error_jobRaises a protocol-level error: `failed` with an inlined `error`.read
quarterly_revenueShow quarterly revenue as a bar chart.read
queryreturn []read
query_dataassert connection.is_openread
query_dbreturn fread
quick_taskreturn value * 2read
quick_toolreturn value * 2read
read_itval = await ctx.get_state(read
refreshCollect fresh system stats.read
regular_toolreturnread
reject_requestReject a pending request and return updated lists.read
rememberfacts = await session.get(read
remote_task_toolA remote tool that supports tasksread
reportreturn noteread
return_audioreturn Audio(path=str(test_audio))read
return_boolreturn Trueread
return_bytesreturn bread
return_dataclassreturn PersonDataclass(name=read
return_datetimereturn datetime(2025, 11, 5, 12, 30, 45)read
return_dictreturn {read
return_embedded_resourcereturn EmbeddedResource(read
return_empty_dictreturn {}read
return_empty_listreturn []read
return_filereturn File(path=str(test_file))read
return_floatreturn 3.14159read
return_image_contentreturn ImageContent(read
return_image_datareturn Image(data=test_image.read_bytes(), format=read
return_image_pathreturn Image(path=str(test_image))read
return_intreturn 42read
return_listreturn [read
return_mixed_contentreturn [read
return_modelreturn UserData(name=read
return_nonereturn Noneread
return_optionalreturnread
return_optional_nonereturn Noneread
return_pathreturn Path(read
return_resource_linkreturn ResourceLink(read
return_stringreturnread
return_text_contentreturn TextContent(type=read
return_tuplereturn (42,read
return_typeddictreturn {read
return_unionreturnread
return_union_intreturn 123read
return_uuidreturn UUID(read
sales_chartShow monthly online vs. retail sales as a bar chart.read
sales_dashboardCompany sales dashboard with KPIs, revenue trends, segment breakdown, and recent deals.read
sample_toolreturn x * 2read
200 of 305 tools listed; the bar and the counts include all of them.

Safer alternatives

Audit history

  1. ✕BLOCK F 27 / 100

    Source changed, verdict held · 9bfb2e369f85

  2. ✕BLOCK F 27 / 100

    First audit · cfbc52f849e6

README badge

Badges show the current verdict, BLOCK included

ModelsAtlas: BLOCK FMODELSATLASBLOCK · F

A badge cannot be hidden by the maintainer while the verdict is BLOCK. Fix the findings, push, and the re-audit updates it.

Questions about FastMCP MCP server

What is the FastMCP MCP server?
🚀 The fast, Pythonic way to build MCP servers and clients.
What tools does FastMCP expose?
200 in total: 265 read-only, 37 that write, and 3 that can delete or overwrite (confirm_delete, delete_item, reset_user_password). Every one is listed on this page with its risk.
Is FastMCP safe to connect to an agent?
No — not without reading the findings first. The audit graded it F (27/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 3 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does FastMCP need?
It reads AUTH0_CONFIG_URL, AUTHKIT_DOMAIN, FASTMCP_GITHUB_TOKEN, FASTMCP_SERVER_AUTH_AWS_COGNITO_AWS_REGION, FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID, FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET, FASTMCP_SERVER_AUTH_AWS_COGNITO_USER_POOL_ID, FASTMCP_SERVER_AUTH_AZURE_CLIENT_ID, FASTMCP_SERVER_AUTH_AZURE_CLIENT_SECRET, FASTMCP_SERVER_AUTH_AZURE_TENANT_ID, FASTMCP_SERVER_AUTH_CLERK_CLIENT_ID and FASTMCP_SERVER_AUTH_CLERK_CLIENT_SECRET from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does FastMCP run?
It speaks sse, stdio and streamable-http, so it runs as a local process your client starts. It is published on PyPI as fastmcp.
How current is this page?
The grade is for one exact copy of the source (9bfb2e369f85), read on 2026-09-20. The repository is watched and re-audited when it changes.
I already installed FastMCP. What should I do?
Remove it from your client's MCP configuration, then rotate any API keys and tokens that were in your environment while it ran.
Can the verdict change?
Yes. The repository is watched and re-audited when its source changes. If the findings are removed the verdict updates, and the history on this page shows it.

Sources

  • jlowin/fastmcp on GitHub — the source we read, its licence, stars and activityObserved · 20 Sep 2026
  • ModelsAtlas trust audit — BLOCK verdict for commit 9bfb2e369f85Observed · 20 Sep 2026

Spotted something wrong? Report a correction · Methodology

Keep going in your AI

Opens with this page as the source. We add nothing else to the prompt.