Metadata-Version: 2.1
Name: fc_mcp
Version: 0.9.2
Summary: MCP server exposing FC operations as MCP tools
Home-page: https://github.com/NXP/fc
Author: Larry Shen
Author-email: larry.shen@nxp.com
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastmcp>=2.3
Requires-Dist: requests
Requires-Dist: PyYAML
Requires-Dist: beautifulsoup4

# FC MCP Server

An [MCP](https://modelcontextprotocol.io/) server, built on
[FastMCP](https://github.com/jlowin/fastmcp), that exposes FC
operations as MCP tools. Under the hood every tool shells out to `fc-client`,
so an AI agent can lock/unlock resources, query status, run console/ssh/power
commands, and drive image deploy/flash workflows.

## Architecture

The server is plugin based. `mcp_server.py` creates the FastMCP instance, loads
the internal plugin, then auto-discovers external plugins.

```
fc_mcp/
  mcp_server.py                # entry point (fc-mcp), transport handling
  mcp_base.py                  # MCPPlugin base class + shared helpers
  mcp_plugins/
    internal/fc_mcp.py         # core fc-client operations (always loaded)
    external/
      uuu_bcu_mcp.py           # UUU/BCU flashing tools (sample external plugin)
      uboot_mcp.py             # U-Boot / predeploy config tools (sample)
```

Any `*_mcp.py` file placed under `mcp_plugins/external/` that exposes a
`Plugin` class is discovered and loaded automatically at startup.

## Installation

From the repository root:

```bash
python setup.py install fc-mcp
```


This installs the `fc-mcp` console entry point. Requires Python >= 3.10 and
`fastmcp >= 2.3` (needed for the Streamable HTTP transport).

## Starting the server

The server supports two transports. **stdio** is the default and is what a
local client (for example `fc-agent`, which launches the server as a
subprocess) uses. **Streamable HTTP** runs the server as a standalone HTTP
service so remote / third-party MCP clients can connect.

### stdio (default)

```bash
fc-mcp
```

The client is responsible for spawning the process and talking JSON-RPC over
stdin/stdout.

### Streamable HTTP

```bash
# Local only (default host 127.0.0.1, port 8000, path /mcp)
fc-mcp --transport http

# Expose to the network
fc-mcp --transport http --host 0.0.0.0 --port 8000 --path /mcp
```

Clients then connect to `http://<host>:<port><path>`, e.g.
`http://127.0.0.1:8000/mcp`.

### Options

Every flag has a matching environment variable, so the server can be configured
in containers/services without CLI arguments. CLI flags take precedence.

| Flag          | Environment variable | Default     | Description                                        |
| ------------- | -------------------- | ----------- | -------------------------------------------------- |
| `--transport` | `FC_MCP_TRANSPORT`   | `stdio`     | Transport mode: `stdio` or `http`.                 |
| `--host`      | `FC_MCP_HOST`        | `127.0.0.1` | Bind host (HTTP transport only).                   |
| `--port`      | `FC_MCP_PORT`        | `8000`      | Bind port (HTTP transport only).                   |
| `--path`      | `FC_MCP_PATH`        | `/mcp`      | URL path the MCP endpoint is served on (HTTP only).|
| _(none)_      | `FC_MCP_AUTH_TOKEN`  | _(unset)_   | Static Bearer token for HTTP transport (env only). |

Example using environment variables:

```bash
export FC_MCP_TRANSPORT=http
export FC_MCP_HOST=0.0.0.0
export FC_MCP_PORT=9000
fc-mcp
# -> http://0.0.0.0:9000/mcp
```

## Authentication (HTTP transport)

By default the HTTP endpoint is **unauthenticated** — anyone who can reach
`http://<host>:<port><path>` can invoke every tool. When exposing the server on
a network (`--host 0.0.0.0`), enable static Bearer-token auth by setting the
`FC_MCP_AUTH_TOKEN` environment variable:

```bash
export FC_MCP_TRANSPORT=http
export FC_MCP_HOST=0.0.0.0
export FC_MCP_AUTH_TOKEN="$(openssl rand -hex 32)"
fc-mcp
```

Behavior:

- If `FC_MCP_AUTH_TOKEN` is unset or empty, the server runs without auth
  (backward compatible).
- If set, every request must include `Authorization: Bearer <token>`;
  otherwise the server responds with `401 Unauthorized`.
- The token is only enforced for HTTP transport. stdio transport ignores it.

The token is intentionally read **only from an environment variable**, not from
a CLI flag: command-line arguments are visible to other local users via `ps` /
`/proc/<pid>/cmdline` (and leak into shell history), whereas
`/proc/<pid>/environ` is readable only by the process owner and root.

Client config with a Bearer token:

```json
{
  "mcpServers": {
    "fc": {
      "url": "http://127.0.0.1:8000/mcp",
      "headers": {
        "Authorization": "Bearer <token>"
      }
    }
  }
}
```

## Connecting a third-party MCP client

For HTTP transport, point the client at the server URL. A typical MCP client
config entry looks like:

```json
{
  "mcpServers": {
    "fc": {
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}
```

For stdio transport, configure the client to launch the process instead:

```json
{
  "mcpServers": {
    "fc": {
      "command": "fc-mcp"
    }
  }
}
```

## Available tools

Grouped by purpose (see the plugin sources for full signatures):

- **Resource management** (`mcp_plugins/internal/fc_mcp.py`):
  `lock`, `unlock`, `status`, `cluster_info`, `all_locks`,
  `advanced_features`, `get_console_names`, `set_comment`.
- **Command execution** (`mcp_plugins/internal/fc_mcp.py`):
  `get_fc_command` (build a command string), `fc_command` (run or return
  ssh/console/power/scp/rsync commands).
- **Deploy / flash** (`mcp_plugins/external/uuu_bcu_mcp.py`):
  `boot_mode_switch`, `flash_usb_boot_nexus`, `flash_usb_boot_uri`,
  `flash_non_usb_boot_uri`.
- **U-Boot / predeploy** (`mcp_plugins/external/uboot_mcp.py`):
  `get_board_server_ip`, `get_uboot_config_uri`, `get_uboot_config_nexus`,
  `list_available_boards`.

## Extending with plugins

Add a new `*_mcp.py` file under `mcp_plugins/external/` that defines a `Plugin`
class subclassing `MCPPlugin` and implementing `register_tools()`:

```python
from fc_mcp.mcp_base import MCPPlugin


class Plugin(MCPPlugin):
    def register_tools(self):
        @self.mcp.tool()
        def my_tool(resource_id: str) -> dict:
            """Describe what the tool does for the agent."""
            ...
            return {"success": True}
```

The file is picked up automatically the next time the server starts.
