mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-20 04:24:17 +02:00
commit
ba94bf6bbb
6 changed files with 42 additions and 47 deletions
|
|
@ -23,7 +23,3 @@ def desktop() -> list[str]:
|
|||
def add(a: int, b: int) -> int:
|
||||
"""Add two numbers"""
|
||||
return a + b
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
|
|
|
|||
|
|
@ -15,8 +15,13 @@ def echo_tool(text: str) -> str:
|
|||
return text
|
||||
|
||||
|
||||
@mcp.resource("echo://static")
|
||||
def echo_resource() -> str:
|
||||
return "Echo!"
|
||||
|
||||
|
||||
@mcp.resource("echo://{text}")
|
||||
def echo_resource(text: str) -> str:
|
||||
def echo_template(text: str) -> str:
|
||||
"""Echo the input text"""
|
||||
return f"Echo: {text}"
|
||||
|
||||
|
|
@ -24,7 +29,3 @@ def echo_resource(text: str) -> str:
|
|||
@mcp.prompt("echo")
|
||||
def echo_prompt(text: str) -> str:
|
||||
return text
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,3 @@ def take_screenshot() -> Image:
|
|||
# if the file exceeds ~1MB, it will be rejected by Claude
|
||||
screenshot.convert("RGB").save(buffer, format="JPEG", quality=60, optimize=True)
|
||||
return Image(data=buffer.getvalue(), format="jpeg")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,3 @@ mcp = FastMCP("Echo Server")
|
|||
def echo(text: str) -> str:
|
||||
"""Echo the input text"""
|
||||
return text
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ def get_claude_config_path() -> Path | None:
|
|||
|
||||
|
||||
def update_claude_config(
|
||||
file: Path,
|
||||
server_name: Optional[str] = None,
|
||||
file_spec: str,
|
||||
server_name: str,
|
||||
*,
|
||||
with_editable: Optional[Path] = None,
|
||||
with_packages: Optional[list[str]] = None,
|
||||
|
|
@ -35,9 +35,8 @@ def update_claude_config(
|
|||
"""Add the MCP server to Claude's configuration.
|
||||
|
||||
Args:
|
||||
file: Path to the server file
|
||||
server_name: Optional custom name for the server. If not provided,
|
||||
defaults to the file stem
|
||||
file_spec: Path to the server file, optionally with :object suffix
|
||||
server_name: Name for the server in Claude's config
|
||||
with_editable: Optional directory to install in editable mode
|
||||
with_packages: Optional list of additional packages to install
|
||||
force: If True, replace existing server with same name
|
||||
|
|
@ -55,46 +54,49 @@ def update_claude_config(
|
|||
if "mcpServers" not in config:
|
||||
config["mcpServers"] = {}
|
||||
|
||||
# Use provided server_name or fall back to file stem
|
||||
name = server_name or file.stem
|
||||
if name in config["mcpServers"]:
|
||||
if server_name in config["mcpServers"]:
|
||||
if not force:
|
||||
logger.warning(
|
||||
f"Server '{name}' already exists in Claude config. "
|
||||
f"Server '{server_name}' already exists in Claude config. "
|
||||
"Use `--force` to replace.",
|
||||
extra={"config_file": str(config_file)},
|
||||
)
|
||||
return False
|
||||
logger.info(
|
||||
f"Replacing existing server '{name}' in Claude config",
|
||||
f"Replacing existing server '{server_name}' in Claude config",
|
||||
extra={"config_file": str(config_file)},
|
||||
)
|
||||
|
||||
# Build uv run command
|
||||
args = ["run"]
|
||||
args = ["run", "--with", "fastmcp"]
|
||||
|
||||
if with_editable:
|
||||
args.extend(["--with-editable", str(with_editable)])
|
||||
|
||||
# Always include fastmcp
|
||||
args.extend(["--with", "fastmcp"])
|
||||
|
||||
# Add additional packages
|
||||
if with_packages:
|
||||
for pkg in with_packages:
|
||||
if pkg:
|
||||
args.extend(["--with", pkg])
|
||||
|
||||
args.append(str(file))
|
||||
# Convert file path to absolute before adding to command
|
||||
# Split off any :object suffix first
|
||||
if ":" in file_spec:
|
||||
file_path, server_object = file_spec.rsplit(":", 1)
|
||||
file_spec = f"{Path(file_path).resolve()}:{server_object}"
|
||||
else:
|
||||
file_spec = str(Path(file_spec).resolve())
|
||||
|
||||
config["mcpServers"][name] = {
|
||||
# Add fastmcp run command
|
||||
args.extend(["fastmcp", "run", file_spec])
|
||||
|
||||
config["mcpServers"][server_name] = {
|
||||
"command": "uv",
|
||||
"args": args,
|
||||
}
|
||||
|
||||
config_file.write_text(json.dumps(config, indent=2))
|
||||
logger.info(
|
||||
f"Added server '{name}' to Claude config",
|
||||
f"Added server '{server_name}' to Claude config",
|
||||
extra={"config_file": str(config_file)},
|
||||
)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ app = typer.Typer(
|
|||
|
||||
|
||||
def _build_uv_command(
|
||||
file: Path,
|
||||
file_spec: str,
|
||||
with_editable: Optional[Path] = None,
|
||||
with_packages: Optional[list[str]] = None,
|
||||
) -> list[str]:
|
||||
"""Build the uv run command."""
|
||||
"""Build the uv run command that runs a FastMCP server through fastmcp run."""
|
||||
cmd = ["uv"]
|
||||
|
||||
cmd.extend(["run", "--with", "fastmcp"])
|
||||
|
|
@ -41,7 +41,8 @@ def _build_uv_command(
|
|||
if pkg:
|
||||
cmd.extend(["--with", pkg])
|
||||
|
||||
cmd.append(str(file))
|
||||
# Add fastmcp run command
|
||||
cmd.extend(["fastmcp", "run", file_spec])
|
||||
return cmd
|
||||
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ def _import_server(file: Path, server_object: Optional[str] = None):
|
|||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
# If no object specified, try __main__ block
|
||||
# If no object specified, try common server names
|
||||
if not server_object:
|
||||
# Look for the most common server object names
|
||||
for name in ["mcp", "server", "app"]:
|
||||
|
|
@ -97,7 +98,9 @@ def _import_server(file: Path, server_object: Optional[str] = None):
|
|||
return getattr(module, name)
|
||||
|
||||
logger.error(
|
||||
f"No server object found in {file}. Please specify the object name with file:object syntax.",
|
||||
f"No server object found in {file}. Please either:\n"
|
||||
"1. Use a standard variable name (mcp, server, or app)\n"
|
||||
"2. Specify the object name with file:object syntax",
|
||||
extra={"file": str(file)},
|
||||
)
|
||||
sys.exit(1)
|
||||
|
|
@ -178,7 +181,7 @@ def dev(
|
|||
)
|
||||
|
||||
try:
|
||||
uv_cmd = _build_uv_command(file, with_editable, with_packages)
|
||||
uv_cmd = _build_uv_command(file_spec, with_editable, with_packages)
|
||||
# Run the MCP Inspector command
|
||||
process = subprocess.run(
|
||||
["npx", "@modelcontextprotocol/inspector"] + uv_cmd,
|
||||
|
|
@ -229,7 +232,12 @@ def run(
|
|||
),
|
||||
] = None,
|
||||
) -> None:
|
||||
"""Run a FastMCP server."""
|
||||
"""Run a FastMCP server.
|
||||
|
||||
The server can be specified in two ways:
|
||||
1. Module approach: server.py - runs the module directly, expecting a server.run() call
|
||||
2. Import approach: server.py:app - imports and runs the specified server object
|
||||
"""
|
||||
file, server_object = _parse_file_path(file_spec)
|
||||
|
||||
logger.debug(
|
||||
|
|
@ -338,7 +346,7 @@ def install(
|
|||
name = file.stem
|
||||
|
||||
if claude.update_claude_config(
|
||||
file,
|
||||
file_spec,
|
||||
name,
|
||||
with_editable=with_editable,
|
||||
with_packages=with_packages,
|
||||
|
|
@ -348,7 +356,3 @@ def install(
|
|||
else:
|
||||
print(f"Failed to install {name} in Claude app")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue