any2mcp
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., "@any2mcpserve the functions in kpi_calculations.py"
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.
any2mcp
Turn any Python module into an MCP server — without handing a language model your shell.
You have a file full of useful Python functions and you want an agent to call them. Today that means importing an MCP framework and decorating every function — so your business logic now depends on MCP.
any2mcp skips that. Point it at a module and every public function becomes a fully-schematized MCP tool, with argument types and descriptions derived from the type hints and docstrings you already wrote:
any2mcp ./tools.pyBut "expose every function" is a dangerous default, and most MCP tooling stops there. If your module happens to contain a run_shell() or a delete_path(), that naive approach just gave a language model your machine.
So any2mcp reads your code before it exposes it:
$ any2mcp examples/devtools.py --risk-report
any2mcp risk report: examples/devtools.py
policy: guard (allows up to 'moderate')
RISK TOOL CAPABILITIES STATUS
-------- ----------------- ------------ -------
safe word_count - exposed
low read_project_file fs-read exposed
- .read_text (line 36) [heuristic]
low list_directory fs-read exposed
- os.listdir (line 44)
moderate write_note fs-write exposed
- .write_text (line 50) [heuristic]
low parse_json_file fs-read exposed
- open (line 56)
high run_shell subprocess BLOCKED
- subprocess.run (line 66)
! blocked: risk 'high' (subprocess) exceeds policy 'guard' (max 'moderate')
high delete_path fs-delete BLOCKED
- shutil.rmtree (line 85)
- .unlink (line 87) [heuristic]
! blocked: risk 'high' (fs-delete) exceeds policy 'guard' (max 'moderate')
5 exposed, 2 blocked.The two dangerous functions are not exposed, and no flags were needed to get that.
The difference
Before — one decorator per function, in a file that now depends on MCP:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("calculator")
@mcp.tool()
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide a by b."""
return a / b
# ...repeat for every function, forever
if __name__ == "__main__":
mcp.run()After — your module stays plain Python and knows nothing about MCP:
# calculator.py — no imports, no decorators
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
def divide(a: float, b: float) -> float:
"""Divide a by b."""
return a / bany2mcp calculator.pyRelated MCP server: py2mcp
Install
pip install any2mcp
# or, with uv:
uv tool install any2mcpNot yet on PyPI? Install straight from source:
uv tool install "git+https://github.com/SanoberRehman/any2mcp"
Quickstart
any2mcp tools.py --risk-report # audit what each function can reach
any2mcp tools.py --list # show the exposed tools + JSON schemas
any2mcp tools.py # serve over stdio
any2mcp tools.py:add # expose only `add`
any2mcp tools.py --exclude '_*' # filter with globs
any2mcp mypackage.tools # a dotted, importable module works tooThe safety model
This is the part worth reading carefully, because the guarantees are uneven and it matters which is which.
What is enforced
A blocked function is never registered as a tool. It is absent from tools/list, so the model cannot see it, cannot call it, and cannot talk its way past it. There is no confirmation token to forge and no runtime check to race — the tool simply does not exist on the server.
You can watch this happen against a real MCP client:
$ python examples/demo_safety.py
=== any2mcp devtools.py (default policy: guard) ===
tools visible to the model: ['word_count', 'read_project_file', 'list_directory', 'write_note', 'parse_json_file']
run_shell: withheld; calling it anyway -> Unknown tool: run_shell
delete_path: withheld; calling it anyway -> Unknown tool: delete_path
word_count still works -> {"words": 3, "lines": 1, "characters": 18}What is a heuristic
Which functions get classified as risky. any2mcp parses your module and looks for calls that reach the filesystem, the network, subprocesses, or the dynamic-execution builtins. It resolves import aliases, so both of these are caught:
import subprocess as sp
def a(cmd): sp.run(cmd) # -> subprocess (high)
from os import system as sh
def b(cmd): sh(cmd) # -> subprocess (high)and it follows calls within your module, so a wrapper inherits its helper's capabilities:
def _upload(data): requests.post("https://...", data=data)
def publish(data): _upload(data) # -> network, "via _upload()"But static analysis is not sound, and indirection defeats it:
def sneaky(cmd):
getattr(os, "system")(cmd) # -> reported SAFE. Not detected.So a safe classification means "no known-risky call was found", never "this function is harmless". These blind spots are asserted in tests/test_risk.py under TestDocumentedBlindSpots, so this claim cannot quietly drift into implying more than it should.
What it is not
any2mcp is not a sandbox. Tools that are exposed run in-process with your full privileges. The policy decides what gets offered to a model; it does not contain what happens next.
Importing a module also executes its top-level code. That is why --risk-report never imports a file target — it works from source, so you can audit code before running any of it, and even audit a module whose dependencies you don't have installed.
Policies
Policy | Allows | Use it when |
| everything | You have read the code and want the 0.1 behaviour. |
| up to | General use. Blocks subprocesses, |
| up to | The agent should look but not touch. |
|
| Pure computation, no side effects of any kind. |
Overrides, in order of precedence — naming a specific tool beats a category rule, and an explicit deny always wins:
any2mcp tools.py --deny-tool 'admin_*' # never expose these
any2mcp tools.py --allow-tool run_shell # expose this one on purpose
any2mcp tools.py --deny-capability network # block a whole capabilityCapabilities are fs-read, fs-write, fs-delete, network, subprocess, dynamic-exec, and env.
Use it as a CI gate
--risk-report exits 3 when anything is blocked and 0 when nothing is, so it can fail a build if someone adds a subprocess call to a module you expose to agents:
- run: any2mcp src/agent_tools.py --risk-report --format jsonAudit log
any2mcp tools.py --audit-log calls.jsonlEvery call is appended as one JSON object. Argument names and types are recorded; values are not — tool arguments routinely carry API keys and file contents, and a log that silently copied them to disk would be its own vulnerability. Opt in with --audit-values when you've decided that's appropriate for your data.
{"ts": "2026-07-28T05:45:14.604+00:00", "event": "blocked", "tool": "run_shell",
"risk": "high", "reason": "risk 'high' (subprocess) exceeds policy 'guard' (max 'moderate')"}
{"ts": "2026-07-28T05:45:14.612+00:00", "event": "call", "tool": "write_note",
"risk": "moderate", "duration_ms": 0.431, "ok": true,
"args": {"path": "str", "text": "str"}}
{"ts": "2026-07-28T05:45:14.614+00:00", "event": "call", "tool": "word_count",
"risk": "safe", "duration_ms": 0.003, "ok": true, "args": {"text": "str"}}Blocked tools are recorded too, so the log shows what was withheld, not just what ran.
Rich schemas, for free
any2mcp doesn't invent its own type system — it hands each function to the MCP SDK's pydantic machinery, the same code path the official @tool decorator uses. So the hard cases just work: Optional[...], unions, Enum, Literal, list/dict/tuple, pydantic models and dataclasses as parameters, defaults, and async def.
// any2mcp calculator.py --list (excerpt for round_to)
{
"name": "round_to",
"input_schema": {
"properties": {
"value": { "type": "number" },
"ndigits": { "type": "integer", "default": 2 },
"mode": { "$ref": "#/$defs/Rounding", "default": "nearest" }
},
"$defs": { "Rounding": { "enum": ["up", "down", "nearest"], "type": "string" } },
"required": ["value"]
}
}A function whose signature genuinely can't be schematized is skipped with a message on stderr — one unsupported function costs one tool, never the whole server.
Use it with Claude Desktop (or any MCP client)
{
"mcpServers": {
"my-tools": {
"command": "any2mcp",
"args": ["/absolute/path/to/tools.py"]
}
}
}Add "--policy", "readonly" to the args array to tighten it further.
Which functions get exposed?
Resolved in this order:
A
:selector(tools.py:add) exposes exactly that one function.Otherwise, if the module defines
__all__, that list is the allow-list.Otherwise, every public function (no leading underscore) defined in the module — functions merely imported into it are skipped, so
from os.path import joinwon't leak in as a tool.
--include / --exclude globs apply on top, then the policy decides what survives.
Roadmap
Policy file (
any2mcp.toml) so per-tool decisions can be reviewed in gitExpose class methods and
@staticmethodsResources & prompts, not just tools
Taint tracking, to tell
read_file("/etc/passwd")fromread_file(user_path)
OpenAPI and FastAPI conversion are intentionally out of scope — fastmcp already does those well. any2mcp focuses on the gap they leave: plain modules, zero decoration, and a defensible answer to "what did I just expose?"
Development
uv sync
uv run pytest # 127 tests, incl. real MCP client sessions
uv run ruff check .License
MIT — see LICENSE.
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 Servers
- Flicense-qualityDmaintenanceA minimal Python package for easily setting up and running MCP servers and clients, allowing functions to be automatically exposed as tools that LLMs can use with just 2 lines of code.Last updated22
- Alicense-qualityCmaintenanceCreate MCP servers from Python functions instantly, with support for input transformations and store-based CRUD operations.Last updatedMIT
- Alicense-qualityBmaintenanceA dead simple MCP server for exposing your app functions to AI agents like Claude Desktop.Last updated5385MIT
- Alicense-qualityCmaintenanceAutomatically converts Python web backends (FastAPI, Flask, Django) into MCP servers by exposing API routes as MCP tools with near-zero boilerplate.Last updatedMIT
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.
MCP server for generating rough-draft project plans from natural-language prompts.
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/SanoberRehman/any2mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server