mcp-library-builder
Generates MCP servers for LangChain submodules, turning functions such as langchain.chat_models.init_chat_model into callable tools.
Generates MCP servers for LangGraph submodules, turning functions such as langgraph.graph.add_messages into callable tools.
Generates an MCP server for MLflow, exposing functions like register_prompt as callable tools while handling parameter-name collisions.
Generates a standalone MCP server exposing NumPy's module-level functions as callable tools, including routines like dot, median, transpose, and reshape.
Generates a standalone MCP server exposing pandas functions, such as unique, as callable tools.
Generates an MCP server for scikit-learn, exposing its importable top-level functions, such as get_config, as tools.
Generates MCP servers for SciPy, exposing module-level functions as tools; best results come from targeting specific submodules such as scipy.stats.
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., "@mcp-library-builderbuild an MCP server from the pandas library"
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.
mcp-library-builder
Turn any Python library into a real, standalone MCP server โ automatically.
Not toy examples (a calculator, a weather lookup). Real libraries: math,
pandas, requests, simpy, keras, and anything else you can pip install.
Why
Tool/function calling exists because LLMs are unreliable at precise computation and at tracking state accurately. This project takes that to its logical conclusion: an LLM's job is a one-time build step โ reading a library's structure and generating a clean MCP server for it โ never a runtime dependency. Once generated, a server is plain, deterministic Python; using it involves no LLM computation, guessing, or hallucinated state.
Related MCP server: AutoMCP
How it works
flowchart LR
lib["Python library\n(math, pandas, ...)"] --> introspect["Introspect\ninspect"]
introspect --> classify["Classify\nfunction / constructor / method"]
classify --> curate["Curate ๐ง \nLLM picks the useful tools"]
curate --> generate["Generate\nJinja2 templates"]
generate --> validate["Validate\nimport-check"]
validate --> out["Real MCP server\nplain, deterministic Python"]
style curate fill:#fff3cd,stroke:#997404,stroke-width:2pxOnly the highlighted Curate step ever touches an LLM โ deciding which of a library's functions are common enough to be first-class tools. Every other step (introspecting the real library, generating the server, checking that it actually imports) is deterministic Python with zero hallucination risk by construction, since it only ever reads and renders real code.
Status
Phase 1 (this codebase): the full pipeline works end-to-end for stateless
libraries โ including keyword-only parameters, *args/**kwargs, optional
parameters, and libraries containing a function named after the module itself
(or after the generated server's own bindings). It has been swept against 77
real standard-library modules, all of which generate importable servers, and
against combinations of up to 10 libraries in one aggregated bundle (288
tools generated and registered correctly in that run). Stateful,
object-oriented libraries (simpy, keras) are Phase 2.
Tried on real libraries
Past the standard library, this has been run against two genuinely complicated real combinations, unfiltered โ including the failures, which are more informative than the successes:
A real ML-workflow bundle:
numpy+scipy+pandas+scikit-learnmlflow, combined into one server withbuild_aggregated_server. First run: 210 real tools, one process, everything called back computed a correct answer (numpy_zeros,pandas_unique,sklearn_get_config, ...). It also found two real bugs, both since fixed:
mlflow.register_prompthas a legitimatemodel_configparameter that collides with a name Pydantic reserves internally, which briefly took the entire build down. Fixed by renaming just that one parameter in the generated wrapper's own signature (model_configโmodel_config_param) rather than dropping the function โ same fix applied to the pre-existing underscore-prefix case (hashlib.file_digest's_bufsizeโbufsize), which used to be dropped outright and is now a real, callable tool too.numpy's most-used functions (
mean,sum,dot,median, ...) were entirely invisible โ not even logged โ because numpy wraps them in a private dispatcher typeinspect.isfunction/isbuiltindoesn't recognize. Broadening the check toinspect.isroutine(still verified to exclude ordinary callable objects) took numpy alone from 60 to 245 introspectable functions in this same bundle.mean/sumthemselves still don't make the final tool list โ they have a separate, already-handled problem (a sentinel default that isn't a literal, same class of issue aspandas.read_csv) โ but they're now visibly skipped with a reason instead of silently absent, and most of their siblings (dot,median,transpose,reshape, ...) are fully recovered.
Rerun with both fixes: 397 tools, one process. (
tensorflow/kerasstill couldn't be included โ no PyPI build of TensorFlow exists yet for the Python version this was run on, and Keras won't import without a working TensorFlow backend. Not a limitation of this tool.)The snake bites its own tail: this project's own
generator/curation.pyimportslangchain.chat_models.init_chat_modelto power its LLM step. Pointed atlangchain.chat_modelsandlanggraph.graphโ the exact modules this tool itself depends on โ it correctly generatedlangchain_chat_models_init_chat_modelandlanggraph_graph_add_messagesas real, working tools.add_messages, called with reallangchain_core.messagesobjects, returned the exact merged result its own docstring documents.
See Limitations for what these runs still reveal about where the tool's real edges are.
Install
pip install -e ".[dev]"
cp .env.example .env # fill in an API key for curationUsage
python -m generator.serverThis starts the generator's own MCP server, exposing two tools:
build_mcp_server(library_name: str) -> strโ generates a server for the named importable library and returns the path to the generated file. Output goes to./generated_servers/<library_name>/server.py, relative to the directory you run the tool from.build_aggregated_server(library_names: list[str], bundle_name: str) -> strโ generates one combined server spanning several importable libraries, so a project needing multiple libraries gets a single MCP process and a single client config entry instead of one per library. Each library's tools are prefixed with its own name (math_sqrt,pandas_read_csv, ...) to avoid collisions between libraries. A library that fails is skipped rather than failing the whole build; output goes to./generated_servers/<bundle_name>/server.py.
flowchart TB
subgraph withoutAgg["Without aggregation โ one process per library"]
direction LR
m1["math server"]
p1["pandas server"]
r1["requests server"]
end
subgraph withAgg["One build_aggregated_server call โ one process"]
direction LR
bundle["math_sqrt ยท pandas_read_csv ยท requests_get ยท ..."]
end
withoutAgg -.-> withAggGeneration is validated before it is reported as successful: the curated
function list is checked against what introspection actually found, and the
generated module is imported. A run that would produce unusable output raises
generator.server.GenerationError rather than handing back a path to code
nobody checked.
Individual functions that cannot be expressed as MCP tools are skipped so the
rest of the library still generates โ a default value that is not a Python
literal (shutil.copytree's copy_function=<function copy2 at 0x...>), or a
signature inspect cannot read at all (math.log). A parameter name MCP
tool registration would otherwise reject (a leading _, or a collision with
a Pydantic-reserved name) is renamed rather than costing the function โ
see Limitations. Each skip that does happen is reported at
INFO on the generator.introspection logger, with the reason.
What a generated server looks like
build_mcp_server("math"), curated down to just sqrt, produces this โ
real output, not a mockup:
# -*- coding: utf-8 -*-
"""Generated MCP server for math.
DO NOT EDIT BY HAND โ regenerate via generator.build_mcp_server().
"""
from mcp.server.mcpserver import MCPServer as _MCPServer
import math as _lib
_server = _MCPServer(name="math-mcp-server")
@_server.tool()
def sqrt(x: float) -> float:
'Return the square root of x.'
return _lib.sqrt(x)
if __name__ == "__main__":
_server.run()No LLM calls anywhere in that file โ it's a plain, deterministic wrapper
around the real math.sqrt, readable and auditable like any other generated
code. An aggregated bundle looks the same, just with one import ... as _<library> line and one @_server.tool() function per promoted function
across every requested library, each tool name prefixed with its own
library's name (math_sqrt, time_time, ...).
Using a generated server
The output is a normal stdio MCP server โ point any MCP client at it the same way you'd point it at a hand-written one. For Claude Desktop or Claude Code, add it to the client's MCP server config:
{
"mcpServers": {
"math": {
"command": "python",
"args": ["generated_servers/math/server.py"]
}
}
}For an aggregated bundle, point at generated_servers/<bundle_name>/server.py
instead โ one config entry covers every library in that bundle.
Limitations
Found through actual use, not guessed at upfront:
Only module-level plain functions are introspected โ no classes, no methods, no state. This is why a library organized around objects rather than free functions can look nearly empty:
scipy's bare top level yields 1 function,sklearn's yields 5 (config utilities, nottrain_test_splitor any estimator), andlangchain/langgraph's yield 0 โ their real API lives one or two levels down, in submodules or classes this tool doesn't walk yet. Point it at the specific submodule you actually want (scipy.stats,langchain.chat_models) rather than the bare package name. Stateful/object-oriented support is the planned Phase 2.A parameter name MCP tool registration would otherwise reject โ a leading
_, or a collision with a Pydantic-reserved name likemodel_configโ is renamed in the generated wrapper's own signature rather than costing the whole function.hashlib.file_digest's_bufsizebecomesbufsize;mlflow.register_prompt'smodel_configbecomesmodel_config_param; the real call still uses the library's real keyword. Only still skipped (and logged) if the rename itself would collide with another parameter of the same function.A default value that isn't a literal Python expression still costs the function.
shutil.copytree'scopy_function=<function copy2 ...>, numpy'skeepdims=<no value>sentinel on many reduction functions,pandas.read_csv'ssep=<no_default>โ none of these can be renamed away, since the problem is the value, not the name. Safely skipped and logged; one bad function never takes down the rest of a library or bundle, but the promoted tool list is sometimes narrower than the library's real surface.Curation quality depends on the LLM you point it at. Every real trial above used a stand-in that promotes everything introspection found, to stress-test the generation pipeline itself rather than an LLM's judgment about what's "useful" โ that judgment call hasn't been evaluated yet.
Contributing
This was built out of curiosity, to see if it'd be useful to someone โ consider this an open invitation rather than a finished product. Concretely useful things to try or pick up:
Try it on a library not listed above and open an issue with what happened โ especially the failures. A silent skip nobody logged, or a new whole-build-breaking collision, is exactly the kind of thing real use finds and a test suite doesn't โ both
model_configand numpy's dispatcher-wrapped functions were found this way and are now fixed.Submodule walking โ so
build_mcp_server("scipy.stats")doesn't require knowing the submodule name upfront.Phase 2: class/state support โ the biggest single gap. Most of what makes
pandas,sklearn, andkerasactually useful is object-oriented, and none of it is reachable yet.Anything in Limitations above.
PRs and issues both welcome.
Running the tests
pip install -e ".[dev]"
pytest -v137 tests, real behavior throughout: generated code is actually written to disk, imported, and called โ nothing is mocked except the LLM curation call itself. CI runs this same suite, plus linting, against Python 3.10 through 3.14 on every push and pull request.
Linting
ruff check .
ruff format generator/ tests/ruff format is deliberately scoped to the actual source directories, not
the whole repo โ it also reformats fenced code blocks inside .md files,
which would silently drift the README's real, verified generated-server
sample away from being byte-for-byte accurate.
License
MIT
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
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Nifty's MCP server โ exposes tasks, projects, messages, and files as tools for AI agents.
Create guides as MCP servers to instruct coding agents to use your software (library, API, etc).
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA 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.22
- AlicenseNot gradedqualityDmaintenanceAutomatically converts CLI tools, APIs, and programs into MCP servers for LLM and agentic use, enabling rapid integration without manual server implementation.1MIT
- AlicenseNot gradedqualityBmaintenanceAutomatically generates MCP server tools from OpenAPI specifications, enabling LLMs to interact with any API defined by an OpenAPI spec through natural language.19MIT
- AlicenseNot gradedqualityBmaintenanceConvert plain Python modules into MCP servers without decorators or boilerplate, automatically exposing functions as schematized tools.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/linga009/mcp-library-builder'
If you have feedback or need assistance with the MCP directory API, please join our Discord server