Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,3 @@ The app mode determines how Connect runs the content. Manifests must specify the
- Special deployment path for Snowflake Snowpark
- `SPCSConnectServer` class for Snowflake-specific authentication
- JWT generation in `snowflake.py`

### MCP (Model Context Protocol)
- Optional MCP support for deploying MCP servers (Python 3.10+)
- Uses `fastmcp` library when available
- See `mcp_deploy_context.py` for deployment context handling
17 changes: 12 additions & 5 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`--no-set-default` is passed. `CONNECT_SERVER` still takes precedence.
- New `environment` subcommand for managing execution environments on Connect.
- New `integration` subcommand for managing OAuth integrations on Connect.
- Removed minimum Connect version indicators from CLI help for versions older
than 2024 (e.g. `[v2021.08.0+]`), since those releases are no longer supported.
Indicators for 2024 and newer versions are retained.
- Removed references to Posit Cloud from command help and docstrings, as
publishing to Posit Cloud is no longer supported.

### Added

Expand Down Expand Up @@ -71,6 +66,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`uv venv` and `uv sync` to populate the scaffolded project's virtualenv.
`uv` installs as a self-contained wheel from PyPI alongside `rsconnect`.

### Removed

- Removed the experimental `rsconnect mcp-server` command. Modern coding agents
are already able to discover and invoke command-line tools directly, so the
command is no longer needed. The optional `mcp` install extra has also been
removed.
- Removed minimum Connect version indicators from CLI help for versions older
than 2024 (e.g. `[v2021.08.0+]`), since those releases are no longer supported.
Indicators for 2024 and newer versions are retained.
- Removed references to Posit Cloud from command help and docstrings, as
publishing to Posit Cloud is no longer supported.

### Fixed

- Python virtual environments (e.g. `.venv`) in a Node.js project directory are
Expand Down
3 changes: 0 additions & 3 deletions docs/commands/mcp-server.md

This file was deleted.

1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ nav:
- system: commands/system.md
- version: commands/version.md
- write-manifest: commands/write-manifest.md
- mcp-server: commands/mcp-server.md


theme:
Expand Down
2 changes: 0 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,9 @@ test = [
"setuptools_scm[toml]>=3.4",
"twine",
"types-Flask",
"fastmcp==2.12.4; python_version >= '3.10'",
]
keyring = ["keyring>=23.0.0"]
snowflake = ["snowflake-cli"]
mcp = ["fastmcp==2.12.4; python_version >= '3.10'"]
docs = [
"mkdocs-material",
"mkdocs-click",
Expand Down
118 changes: 0 additions & 118 deletions rsconnect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from typing import (
Any,
Callable,
Dict,
ItemsView,
Literal,
Optional,
Expand Down Expand Up @@ -522,123 +521,6 @@ def version():
click.echo(VERSION)


@cli.command(
short_help="Start the Model Context Protocol (MCP) server.",
help=(
"Start a Model Context Protocol (MCP) server to expose rsconnect-python capabilities to AI applications "
"through a standardized protocol interface."
"\n\n"
"The MCP server exposes a single tool:\n\n"
"`get_command_info`:\n\n"
" - Provides detailed parameter schemas for any rsconnect command. "
"This provides context for an LLM to understand how to construct valid rsconnect "
"commands dynamically without hard-coded knowledge of the CLI."
"\n\n"
"System Requirements:\n\n"
" - Python>=3.10\n"
" - fastmcp"
"\n\n"
"The server runs in stdio mode, communicating via standard input/output streams."
"\n\n"
"Usage with popular LLM clients:\n\n"
" - [codex](https://developers.openai.com/codex/mcp/#configuration---cli)\n"
" - [claude code](https://docs.claude.com/en/docs/claude-code/mcp#option-3%3A-add-a-local-stdio-server)\n"
" - [VS Code](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_add-an-mcp-server)\n\n"
"The command `uvx --from rsconnect-python rsconnect mcp-server` is a simple option for use in each of "
"the above options."
),
)
def mcp_server():
try:
from fastmcp import FastMCP
from fastmcp.exceptions import ToolError
except ImportError:
raise RSConnectException(
"The fastmcp package is required for MCP server functionality. "
"Install it with: pip install rsconnect-python[mcp]"
)

mcp = FastMCP("Connect MCP")

# Discover all commands at startup
from .mcp_deploy_context import discover_all_commands

all_commands_info = discover_all_commands(cli)

def get_command_info(
command_path: str,
) -> Dict[str, Any]:
try:
# split the command path into parts
parts = command_path.strip().split()
if not parts:
available_commands = list(all_commands_info["commands"].keys())
return {"error": "Command path cannot be empty", "available_commands": available_commands}

current_info = all_commands_info
current_path = []

for _, part in enumerate(parts):
# error if we find unexpected additional subcommands
if "commands" not in current_info:
return {
"error": f"'{' '.join(current_path)}' is not a command group. Unexpected part: '{part}'",
"type": "command",
"command_path": f"rsconnect {' '.join(current_path)}",
}

# try to return useful messaging for invalid subcommands
if part not in current_info["commands"]:
available = list(current_info["commands"].keys())
path_str = " ".join(current_path) if current_path else "top level"
return {"error": f"Command '{part}' not found in {path_str}", "available_commands": available}

current_info = current_info["commands"][part]
current_path.append(part)

# still return something useful if additional subcommands are needed
if "commands" in current_info:
return {
"type": "command_group",
"name": current_info.get("name", parts[-1]),
"description": current_info.get("description"),
"available_subcommands": list(current_info["commands"].keys()),
"message": f"The '{' '.join(parts)}' command requires a subcommand.",
}
else:
return {
"type": "command",
"command_path": f"rsconnect {' '.join(parts)}",
"name": current_info.get("name", parts[-1]),
"description": current_info.get("description"),
"parameters": current_info.get("parameters", []),
"shell": "bash",
}
except Exception as e:
raise ToolError(f"Failed to retrieve command info: {str(e)}")

# dynamically build docstring with top level commands
# note: excluding mcp-server here
available_commands = sorted(cmd for cmd in all_commands_info["commands"].keys() if cmd != "mcp-server")
commands_list = "\n ".join(f"- {cmd}" for cmd in available_commands)

get_command_info.__doc__ = f"""Get the parameter schema for any rsconnect command.

Returns information about the parameters needed to construct an rsconnect command
that can be executed in a bash shell. Supports nested command groups of arbitrary depth.

Available top-level commands:
{commands_list}

:param command_path: space-separated command path (e.g., 'version', 'deploy notebook', 'content build add')
:return: dictionary with command parameter schema and execution metadata
"""

mcp.tool(get_command_info)

mcp.run()


def _test_server_and_api(server: str, api_key: str, insecure: bool, ca_cert: str | None):
"""
Test the specified server information to make sure it works. If so, a
Expand Down
115 changes: 0 additions & 115 deletions rsconnect/mcp_deploy_context.py

This file was deleted.

Loading
Loading