py2mcp.main#

Build a FastMCP server from Python functions, reference strings, or a store.

Each builder returns a FastMCP server object with one tool per function and does not run it; py2mcp.serve (stdio) and py2mcp.http (Streamable HTTP) do the running. All three accept middleware, instructions, prompts and resources and attach them at construction; mk_mcp_server and mk_mcp_from_refs take the server name directly, while mk_mcp_from_store takes the singular item noun instead and derives the server name from it (server_name overrides).

Main entry points:

  • mk_mcp_server: register callables as tools

  • mk_mcp_from_refs: resolve 'module:function' strings, then the same

  • mk_mcp_from_store: generate list/get/set/delete tools over a MutableMapping

>>> from py2mcp.main import mk_mcp_from_refs
>>> mk_mcp_from_refs(['os.path:basename'], name='Paths').name
'Paths'

Functions

mk_mcp_from_refs(refs, *[, name, ...])

Create an MCP server from 'module:function' reference strings.

mk_mcp_from_store(store, *[, name, plural, ...])

Create an MCP server from a MutableMapping with CRUD operations.

mk_mcp_server(funcs, *[, name, input_trans, ...])

Create an MCP server from Python functions.

py2mcp.main.mk_mcp_from_refs(refs, *, name='py2mcp Server', input_trans=None, auth=None, middleware=None, instructions=None, prompts=None, resources=None, icons=None, annotations=None)[source]#

Create an MCP server from 'module:function' reference strings.

Resolves each reference to a callable via py2mcp.util.import_object() and delegates to mk_mcp_server(). One call from config strings to a runnable server — what tools that read tool references from a file (e.g. coact’s mcp backend) need.

Parameters:
Return type:

FastMCP

Returns:

A FastMCP server with one tool per reference, each named after the resolved function.

Raises:

ValueError – A reference has no module or attr part (see py2mcp.util.import_object(), whose import errors propagate too).

Examples

>>> mcp = mk_mcp_from_refs(['os.path:basename', 'os.path:dirname'], name='Paths')
>>> mcp.name
'Paths'

The tools are the resolved functions:

>>> import asyncio
>>> sorted(tool.name for tool in asyncio.run(mcp.list_tools()))
['basename', 'dirname']
>>> asyncio.run(mcp.call_tool('basename', {'p': '/a/b/c.txt'})).content[0].text
'c.txt'

See also

py2mcp.serve.serve_stdio(): build from refs and run over stdio. py2mcp.http.mk_http_app(): build from refs as an ASGI app.

py2mcp.main.mk_mcp_from_store(store, *, name='item', plural='', server_name=None, middleware=None, instructions=None, prompts=None, resources=None, icons=None, annotations=None)[source]#

Create an MCP server from a MutableMapping with CRUD operations.

Generates four tools over the store, list_<plural>, get_<name>, set_<name> and delete_<name>, so any key-value store (a dict, a dol store, a database wrapper) is one call away from being MCP tools. The store is used live: a tool call reads or writes the mapping you passed.

Parameters:
Return type:

FastMCP

Returns:

A FastMCP server with the four CRUD tools.

Examples

>>> import asyncio
>>> projects = {'p1': {'name': 'Project 1'}, 'p2': {'name': 'Project 2'}}
>>> mcp = mk_mcp_from_store(projects, name='project')
>>> mcp.name
'project Store'
>>> sorted(tool.name for tool in asyncio.run(mcp.list_tools()))
['delete_project', 'get_project', 'list_projects', 'set_project']
>>> asyncio.run(mcp.call_tool('get_project', {'key': 'p1'})).structured_content
{'result': {'name': 'Project 1'}}

An irregular plural and an explicit server name:

>>> mcp = mk_mcp_from_store({}, name='entry', plural='entries', server_name='Ledger')
>>> mcp.name
'Ledger'
>>> sorted(tool.name for tool in asyncio.run(mcp.list_tools()))
['delete_entry', 'get_entry', 'list_entries', 'set_entry']

See also

py2mcp.util.store_to_funcs(): the CRUD functions without a server. mk_mcp_server(): expose your own functions instead.

py2mcp.main.mk_mcp_server(funcs, *, name='py2mcp Server', input_trans=None, auth=None, middleware=None, instructions=None, prompts=None, resources=None, icons=None, annotations=None)[source]#

Create an MCP server from Python functions.

This is the main entry point for py2mcp. Pass one or more functions, and get back a FastMCP server ready to run. Each function becomes one tool, named after the function, with its signature and docstring as the tool’s schema and description.

Parameters:
  • funcs (Union[Callable, Iterable[Callable]]) – A function or iterable of functions to expose as MCP tools.

  • name (str) – Name of the MCP server.

  • input_trans (Optional[Callable[[dict], dict]]) – Called with the dict of keyword arguments of every tool call; the dict it returns is what the function receives. Build one with py2mcp.mk_input_trans(). None passes arguments through untouched.

  • auth (Optional[Any]) – Optional fastmcp.server.auth provider attached at construction — used by the remote (HTTP) path for OAuth 2.1 (see py2mcp.http). None (the default) leaves the server unauthenticated, which is correct for the local stdio path.

  • middleware (Optional[Any]) – Optional FastMCP middleware (a single middleware or a list), attached at construction, for cross-cutting concerns that must wrap every tool call — usage metering, cost logging, audit, rate limiting. Preferred over decorating each tool: you can’t forget to wrap one (a missed paid tool means untracked cost). On the remote path auth runs first, so a middleware can read the authenticated caller via fastmcp.server.dependencies.get_access_token().

  • instructions (Optional[str]) – Optional natural-language description of the server, surfaced to the client/model as the server’s instructions — a good place to explain what the tools do and the intended workflow. None (default) leaves it unset.

  • prompts (Union[Callable, Iterable[Callable], None]) – Optional callable or iterable of callables to register as MCP prompts (via FastMCP’s @mcp.prompt), so a prompts-and-tools server can be built declaratively in one call instead of reaching past the builder to register prompts by hand on the returned server.

  • resources (Optional[Mapping[str, Callable]]) – Optional {uri: callable} mapping to register as MCP resources (via FastMCP’s @mcp.resource(uri)) — the callable is invoked to produce the resource’s content when a client reads uri.

  • icons (Optional[Any]) – Optional server icon(s), sent in the MCP serverInfo so a client (e.g. claude.ai’s connector list) can show one: an mcp.types.Icon, a dict of its fields, a bare src (URL or data: URI), or a list of those. None (default) sends none.

  • annotations (Optional[Any]) – Optional per-tool MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so a host can gate tools by them instead of treating all as destructive. Either a {tool_name: annotations} mapping (tools absent from it get none), or a callable func -> annotations | None evaluated per function (e.g. to derive them from your own side-effect metadata). Each value is an mcp.types.ToolAnnotations or a dict of its fields. None (default) sets none.

Return type:

FastMCP

Returns:

A FastMCP server instance ready to run, with one tool per function.

Examples

>>> def add(a: int, b: int) -> int:
...     '''Add two numbers'''
...     return a + b
>>> mcp = mk_mcp_server(add)
>>> mcp.name
'py2mcp Server'

Several functions, a server name, and a look at the registered tools:

>>> import asyncio
>>> def greet(name: str) -> str:
...     return f"Hello, {name}!"
>>> mcp = mk_mcp_server([add, greet], name="Math & Greetings")
>>> mcp.name
'Math & Greetings'
>>> sorted(tool.name for tool in asyncio.run(mcp.list_tools()))
['add', 'greet']

Calling a tool the way an MCP client would:

>>> result = asyncio.run(mcp.call_tool('add', {'a': 2, 'b': 3}))
>>> result.structured_content
{'result': 5}

Prompts and resources, declared alongside the tools:

>>> def summarize_request(topic: str) -> str:
...     return f"Summarize the latest on {topic}."
>>> def schema() -> dict:
...     return {"type": "object"}
>>> mcp = mk_mcp_server(
...     add,
...     prompts=summarize_request,
...     resources={"schema://analysis": schema},
... )
>>> sorted(p.name for p in asyncio.run(mcp.list_prompts()))
['summarize_request']
>>> [str(r.uri) for r in asyncio.run(mcp.list_resources())]
['schema://analysis']

Annotations, by tool name (or a callable func -> annotations):

>>> mcp = mk_mcp_server([add, greet], annotations={'add': {'readOnlyHint': True}})
>>> tools = {t.name: t for t in asyncio.run(mcp.list_tools())}
>>> tools['add'].annotations.readOnlyHint, tools['greet'].annotations
(True, None)

See also

mk_mcp_from_refs(): the same from 'module:function' strings. mk_mcp_from_store(): CRUD tools generated from a mapping. py2mcp.mk_input_trans(): build an input_trans from per-argument converters.