MCP server · Org-owned · Audited from source
FastMCP MCP server
by jlowin/fastmcpApache-2.0 licenceAudited 20 Sep 2026 · source 9bfb2e369f85
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.
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
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
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
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
- —
MEDIUMInventory / provenanceinv.symlink · .claude/skills/code-review
.claude/skills/code-review
- Why
- link not followed
- Fix
- —
MEDIUMInventory / provenanceinv.symlink · .claude/skills/docs
.claude/skills/docs
- Why
- link not followed
- Fix
- —
MEDIUMInventory / provenanceinv.symlink · .claude/skills/fix-issue
.claude/skills/fix-issue
- Why
- link not followed
- Fix
- —
MEDIUMInventory / provenanceinv.symlink · .claude/skills/python-tests
.claude/skills/python-tests
- Why
- link not followed
- Fix
- —
MEDIUMInventory / provenanceinv.symlink · .claude/skills/release
.claude/skills/release
- Why
- link not followed
- Fix
- —
MEDIUMCode injectioncode.dynamic_import · fastmcp_slim/fastmcp/server/__init__.py:14
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
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
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
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
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
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
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
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
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
Excerpt withheld: it is a secret, and we never print one.
- Why
- No further detail recorded for this rule.
- Fix
- —
MEDIUMFilesystem / pathmcp.destructive_tools
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
LOWCode injectioncode.deserialize · .github/scripts/test-ci-workflows.mjs:20
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
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
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.
| Tool | What it does | Risk |
|---|---|---|
confirm_delete | Parks the task on one elicitation before doing the (pretend) deletion. | destructive |
delete_item | Remove an item by ID and return the remaining inventory. | destructive |
reset_user_password | Reset a user | destructive |
_trigger_docket | return | write |
add | return a + b | write |
add_comment | Add a comment to a request. Returns the updated request. | write |
add_item | Add a new item to inventory and return the full list. | write |
add_numbers | Add two numbers | write |
bare_sync_access | headers = get_http_headers() | write |
blocking | import time | write |
calculate | Add two numbers (v1.0). | write |
contact_form | Show a form to create a new contact, with a live contact list below. | write |
context_sync_access | headers = get_http_headers() | write |
coordinated | started.set() | write |
create | Create item | write |
create_project | return | write |
create_user | Create a user. | write |
custom-add | return x + y | write |
custom_save | return name | write |
dynamic_add | Add two numbers with offset | write |
execute_trade | Execute a trade (simulated). | write |
fast_sync_tool | time.sleep(0.01) | write |
modify | Modify the data provided. | write |
query_sync | assert connection.is_open | write |
return_set | return {1, 2, 3} | write |
run | Run something | write |
run_query | ... | write |
save | return f | write |
save_contact | Save a new contact and return the updated list. | write |
admin_tool | return | read |
analyze_data | Filter and analyze sales data. Returns rows, summary, and chart data. | read |
analyze_portfolio | Analyze a portfolio of stock symbols. | read |
annotate | current = trace.get_current_span() | read |
api_health | Show health details for each API endpoint. | read |
approve_request | Approve a pending request and return updated lists. | read |
ask_name | result = await ctx.elicit( | read |
async_echo | Async tool for testing | read |
async_tool | An async tool. | read |
background_tool | return x | read |
bare_tool | info = get_task_context() | read |
batch_process | Process batches. | read |
bg_progress_tool | await progress.set_total(3) | read |
bg_tool | await asyncio.sleep(0.01) | read |
blocked | return | read |
book_flight | return _ask( | read |
boom | raise ValueError( | read |
calc | return | read |
call_api | return f | read |
capture_docket_id | docket_ids.append((call_num, id(docket))) | read |
charge | Charge a payment (v1.0 - basic). | read |
check_both | assert isinstance(docket, Docket) | read |
check_docket | assert isinstance(docket, Docket) | read |
check_headers | headers = _worker_snapshot_headers() | read |
check_permission | return f | read |
check_request_header | return _worker_snapshot_headers().get( | read |
check_token | token = get_access_token() | read |
check_worker_status | return f | read |
checkpoint | if ctx.request_state is None: | read |
claimed_tool | return None | read |
combine | return f | read |
compute | Compute something. | read |
count | return 1 | read |
crunch | ... | read |
custom | A custom tool | read |
custom_name | return str(x) | read |
custom_tool | A custom tool | read |
declared_status | return { | read |
demo | A demo app that exercises various MCP message types. | read |
double | return n * 2 | read |
dynamic_multiply | Multiply two numbers | read |
echo | Echo a message back. | read |
echo_with_logs | Echo a message and emit log notifications. | read |
employee_directory | Show a searchable, sortable employee directory. | read |
enabled | Task enabled | read |
enter_env | await ctx.disable_components(tags={ | read |
error_tool | raise ToolError( | read |
excluded_versioned_tool | return | read |
exit_env | await ctx.reset_visibility() | read |
explicit_tool | return { | read |
explodes | raise MCPError(code=INTERNAL_ERROR, message= | read |
f | return 42 | read |
fail | Always raises an error. | read |
failing_tool | raise ValueError( | read |
farewell | Say farewell in their language. | read |
fast_async_tool | await anyio.sleep(0.01) | read |
fast_tool | return x * 2 | read |
feature_flags | Toggle feature flags with live preview. | read |
fetch | Fetch data from | read |
fetch_data | return ( | read |
filter_by_category | Filter inventory by category. Pass | read |
filter_data | Filter sales data by region and/or product. | read |
finance_tool | return | read |
forbidden | Forbidden tool | read |
forever | await asyncio.Event().wait() | read |
full_name | responses = ctx.input_responses | read |
get_auth_type | auth = headers.get( | read |
get_client_ip | return request.client.host if request.client else | read |
get_market_data | Get current market data for a symbol. | read |
get_my_emails | async with httpx2.AsyncClient() as client: | read |
get_node | Get a node | read |
get_pr | Get a pull request | read |
get_request_details | Get full details for a single request. Available to both model and UI. | read |
get_request_id | return ctx.request_id | read |
get_summary | Return summary statistics for the full dataset. | read |
get_test_file_from_server | No description in the source | read |
get_test_pdf_from_url | No description in the source | read |
get_user_id | return token.claims.get( | read |
get_weather | Get the current weather | read |
greet | Greet someone in their language. | read |
greet_user | return f | read |
guard | calls.append(1) | read |
hidden_tool | return | read |
included_versioned_tool | return | read |
info | return | read |
inspect_items | return { | read |
instant_timeout | await anyio.sleep(0) # Give the event loop a chance to check timeout | read |
internal_tool | return | read |
introspect | return f | read |
leak | raise ValueError( | read |
list_contacts | Return all contacts. Visible to both the model and the UI. | read |
list_requests | List requests, optionally filtered by status. | read |
list_users | List all system users. | read |
log_progress | ctx.report_progress(50, 100, | read |
long_timeout | await anyio.sleep(0.01) | read |
make_tool | return | read |
mixed_audio_list_fn | return [ | read |
mixed_deps | assert isinstance(ctx, Context) | read |
mixed_file_list_fn | return [ | read |
mixed_list_fn | return [ | read |
multi_input | Parks the task on two elicitations at once, so they can be answered separately. | read |
multiply | return x * y | read |
my_function | return f | read |
my_task | # Works transparently in both foreground and background task modes | read |
my_tool | A tool | read |
mytool | return | read |
new_tool | return | read |
no_task_tool | return | read |
normal_tool | return config[ | read |
ok | return | read |
old_tool | return | read |
one | return 1 | read |
one_question | responses = ctx.input_responses | read |
only_v5 | return | read |
pick | return | read |
ping | Ping the server | read |
plan_dinner | Plan a dinner menu, asking the user what they | read |
positional_name | No description in the source | read |
premium_tool | return | read |
private_tool | return f | read |
process_data | return f | read |
progress_tool | await ctx.report_progress(0, 100, | read |
project_overview | Show project details organized in tabs. | read |
protected | return | read |
protocol_error_job | Raises a protocol-level error: `failed` with an inlined `error`. | read |
quarterly_revenue | Show quarterly revenue as a bar chart. | read |
query | return [] | read |
query_data | assert connection.is_open | read |
query_db | return f | read |
quick_task | return value * 2 | read |
quick_tool | return value * 2 | read |
read_it | val = await ctx.get_state( | read |
refresh | Collect fresh system stats. | read |
regular_tool | return | read |
reject_request | Reject a pending request and return updated lists. | read |
remember | facts = await session.get( | read |
remote_task_tool | A remote tool that supports tasks | read |
report | return note | read |
return_audio | return Audio(path=str(test_audio)) | read |
return_bool | return True | read |
return_bytes | return b | read |
return_dataclass | return PersonDataclass(name= | read |
return_datetime | return datetime(2025, 11, 5, 12, 30, 45) | read |
return_dict | return { | read |
return_embedded_resource | return EmbeddedResource( | read |
return_empty_dict | return {} | read |
return_empty_list | return [] | read |
return_file | return File(path=str(test_file)) | read |
return_float | return 3.14159 | read |
return_image_content | return ImageContent( | read |
return_image_data | return Image(data=test_image.read_bytes(), format= | read |
return_image_path | return Image(path=str(test_image)) | read |
return_int | return 42 | read |
return_list | return [ | read |
return_mixed_content | return [ | read |
return_model | return UserData(name= | read |
return_none | return None | read |
return_optional | return | read |
return_optional_none | return None | read |
return_path | return Path( | read |
return_resource_link | return ResourceLink( | read |
return_string | return | read |
return_text_content | return TextContent(type= | read |
return_tuple | return (42, | read |
return_typeddict | return { | read |
return_union | return | read |
return_union_int | return 123 | read |
return_uuid | return UUID( | read |
sales_chart | Show monthly online vs. retail sales as a bar chart. | read |
sales_dashboard | Company sales dashboard with KPIs, revenue trends, segment breakdown, and recent deals. | read |
sample_tool | return x * 2 | read |
Safer alternatives
gleanwork/remote-mcp-server
Remote MCP Server that securely connects Enterprise context with your LLM, IDE, or agent platform of choice.
VRIL-LABS/aliensec-mcp-server
👽 The AlienSec MCP Server is an AlienVault OTX endpoint security scanning MCP server with VirusTotal integration.
getzep/graphiti
Build Real-Time Knowledge Graphs for AI Agents
Audit history
- ✕BLOCK F 27 / 100
Source changed, verdict held ·
9bfb2e369f85 - ✕BLOCK F 27 / 100
First audit ·
cfbc52f849e6
README badge
Badges show the current verdict, BLOCK included
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?
What tools does FastMCP expose?
Is FastMCP safe to connect to an agent?
What credentials does FastMCP need?
How does FastMCP run?
How current is this page?
I already installed FastMCP. What should I do?
Can the verdict change?
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.
- What is the FastMCP MCP server?
- What tools does FastMCP expose?
- Is FastMCP safe to connect to an agent?