Files
Lucas Manuel Rodriguez 56763d13c1 Move fleet-mcp from tools/ to cmd/ (#49044)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** #43544. 

Moves `fleet-mcp` from `tools/fleet-mcp/` to `cmd/fleet-mcp/`. It is
becoming a production server used by customers, so it now lives under
`cmd/` alongside the other Fleet binaries.

Per the module strategy chosen for this move, it **remains a standalone
Go module** (keeps its own `go.mod`/`go.sum` and isolated deps such as
`mark3labs/mcp-go`, `logrus`, `gorilla/websocket`, `godotenv`) — the
root `github.com/fleetdm/fleet/v4` module is unchanged.

### What changed
- `git mv tools/fleet-mcp/ → cmd/fleet-mcp/` (history preserved as
renames).
- Updated all path references:
  - Root `Makefile` `update-go` module list.
- `.github/workflows/test-fleet-mcp.yml` — trigger paths,
`go-version-file`, `working-directory`.
  - `.github/dependabot.yml` — gomod directory.
  - `cmd/fleet-mcp/render.yaml` — `rootDir`.
- `cmd/fleet-mcp/README.md`, `Makefile`, `schema.go` — path
comments/links.
  - `articles/fleet-mcp.md` — README link.
  - Removed the `fleet-mcp/` row from `tools/README.md`.

### Follow-up (not in this PR)
- The Render service's Blueprint file path must be updated from
`tools/fleet-mcp/render.yaml` to `cmd/fleet-mcp/render.yaml` in the
Render dashboard.

## Testing
- `go build .` in `cmd/fleet-mcp` — OK
- `go test -race -count=1 ./...` — `ok fleet-mcp`

- [x] QA'd all new/changed functionality manually
2026-07-09 13:29:09 -03:00

71 lines
3.1 KiB
Makefile

# Fleet MCP — dev/test helpers. Run from cmd/fleet-mcp/.
#
# The MCP reads these (the binary auto-loads a .env in this dir, or export them):
# FLEET_BASE_URL, FLEET_API_KEY, MCP_AUTH_TOKEN (>=32 chars)
# FLEET_API_KEY must belong to an API-only Fleet user, else the binary refuses
# to start (see README "API-only token required").
# FLEET_TLS_SKIP_VERIFY=true # only for a localhost dev Fleet with a self-signed cert
# Quickest setup: cp .env.example .env && edit it (.env is gitignored).
#
# Usage:
# make build
# make tools # list registered tools
# make posture # show the startup token-posture check (stderr)
# make call TOOL=get_total_system_count
# make call TOOL=get_endpoints ARGS='{"per_page":"5"}'
# make call TOOL=run_live_query ARGS='{"sql":"SELECT version FROM os_version","host_ids":"2"}'
# make sse PORT=8137 # run the SSE server (foreground)
#
# Tool output is pretty-printed when `jq` is installed; otherwise raw JSON-RPC.
# No language runtime required beyond a POSIX shell + the built binary.
BIN ?= ./fleet-mcp
TOOL ?=
ARGS ?= {}
PORT ?= 8080
# JSON-RPC handshake lines reused by call/tools.
INIT := {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"make","version":"1"}}}
INITED := {"jsonrpc":"2.0","method":"notifications/initialized"}
.PHONY: help build call tools posture sse
help:
@grep -E '^#' Makefile | sed -e 's/^# \{0,1\}//'
build:
@go build -o fleet-mcp .
# Drive a single tool over stdio. Clean output on success; prints the binary's
# stderr (e.g. a startup Fatalf) instead of going silent on failure.
call: build
@test -n "$(TOOL)" || { echo "usage: make call TOOL=<tool> [ARGS='<json>']"; exit 2; }
@err=$$(mktemp); \
out=$$(printf '%s\n' \
'$(INIT)' \
'$(INITED)' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"$(TOOL)","arguments":$(ARGS)}}' \
| $(BIN) -transport stdio 2>$$err); \
if [ -z "$$out" ]; then echo "no response — startup error:"; cat $$err; rm -f $$err; exit 1; fi; \
rm -f $$err; \
printf '%s\n' "$$out" | if command -v jq >/dev/null 2>&1; then jq -Rr 'fromjson? | select(.id==2) | (.result.content[0].text // .result // .)'; else grep '"id":2'; fi
# List the tools the server registers. Surfaces a startup error (e.g. a
# non-API-only token or unreachable Fleet) instead of printing nothing.
tools: build
@err=$$(mktemp); \
out=$$(printf '%s\n' '$(INIT)' '$(INITED)' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| $(BIN) -transport stdio 2>$$err); \
if [ -z "$$out" ]; then echo "no response — startup error:"; cat $$err; rm -f $$err; exit 1; fi; \
rm -f $$err; \
printf '%s\n' "$$out" | if command -v jq >/dev/null 2>&1; then jq -Rr 'fromjson? | select(.id==2) | .result.tools[].name'; else grep '"id":2'; fi
# Run the startup token check: the binary verifies FLEET_API_KEY is an API-only
# user (logs it, or refuses) on stderr, then exits on stdin EOF.
posture: build
@$(BIN) -transport stdio </dev/null
# Run the SSE server in the foreground (Ctrl-C to stop).
sse: build
PORT=$(PORT) $(BIN)