feat(mcp): scaffold Go module under mcp/ for Claude Desktop bundle

Add a new top-level mcp/ Go module that will host the Claude Desktop MCPB
server. U1 of the Claude Desktop .mcpb bundle plan: scaffold only, no
behavior yet.

- mcp/go.mod targets Go 1.22+ with mark3labs/mcp-go as the planned
  dependency (added in U3 when the server wiring lands).
- mcp/scripts/sync-engine.sh mirrors skills/last30days/scripts/ into
  mcp/vendored/ before each build, keeping the Code skill and Desktop
  bundle on the same engine source.
- Root .gitignore excludes mcp/vendored/ and mcp/build/ so the engine
  mirror and cross-compiled binaries stay local.
This commit is contained in:
Matt Van Horn
2026-05-17 20:42:43 -07:00
parent d9f606ff75
commit 15781bfcc0
6 changed files with 96 additions and 0 deletions
+5
View File
@@ -26,5 +26,10 @@ htmlcov/
# build artifact from scripts/build-skill.sh # build artifact from scripts/build-skill.sh
/dist/ /dist/
# Go MCP bundle build outputs - source of truth for vendored/ stays under
# skills/last30days/scripts/; build/ holds cross-compiled binaries + .mcpb files.
/mcp/vendored/
/mcp/build/
# Internal planning docs (ce:plan output) — keep local, don't publish # Internal planning docs (ce:plan output) — keep local, don't publish
docs/plans/ docs/plans/
+9
View File
@@ -0,0 +1,9 @@
# Mirror of skills/last30days/scripts/, populated by scripts/sync-engine.sh.
# Source of truth lives in the Python skill; never commit the mirror.
vendored/
# Local build output: cross-compiled binaries and packaged .mcpb files.
build/
# Anchor to the mcp/ root so the cmd/last30days-pp-mcp/ package directory
# is not also excluded (subdirs with the same name would otherwise match).
/last30days-pp-mcp
+36
View File
@@ -0,0 +1,36 @@
# last30days-pp-mcp
Go MCP server that wraps the last30days Python engine for Claude Desktop. Packaged as a `.mcpb` bundle (drag-drop install into Claude Desktop).
The MCP server exposes a single `research` tool that mirrors the `/last30days <topic>` slash command available in Claude Code. At runtime the binary extracts the vendored Python engine into a per-user cache and shells out to `python3` to produce the synthesis input Claude renders.
## Architecture
- `cmd/last30days-pp-mcp/` - server entry point
- `internal/engine/` - `embed.FS` of the Python engine + cache extractor + subprocess wrapper
- `internal/tools/` - MCP tool handlers (currently `research`)
- `vendored/` - mirror of `skills/last30days/scripts/`, generated by `scripts/sync-engine.sh` (gitignored)
- `manifest.json` - MCPB v0.3 manifest consumed by Claude Desktop and `printing-press bundle`
## Local build
```bash
# Mirror the Python engine into vendored/.
bash scripts/sync-engine.sh
# Build for the current host.
go build -ldflags "-X main.Version=dev" -o build/last30days-pp-mcp ./cmd/last30days-pp-mcp
# Package as a .mcpb (requires the printing-press binary on PATH).
printing-press bundle . --skip-build --binary build/last30days-pp-mcp
```
The output `.mcpb` lands at `build/last30days-pp-mcp-<os>-<arch>.mcpb`. Drag it into Claude Desktop's Extensions panel to install.
## Runtime requirements
End users need Python 3.12+ on PATH. The bundle ships the engine source but relies on the host interpreter.
## Versioning
The MCPB `manifest.json` version is hand-bumped in the same PR that ships engine changes worth releasing. Release CI stamps the Go binary's `main.Version` from the tag.
+11
View File
@@ -0,0 +1,11 @@
// Package main is the entry point for the last30days MCP server bundled
// as a .mcpb for Claude Desktop. See mcp/README.md for build instructions.
package main
// Version is stamped at build time via -ldflags "-X main.Version=<tag>".
// Defaults to "dev" for local builds.
var Version = "dev"
func main() {
// Wired in U3.
}
+3
View File
@@ -0,0 +1,3 @@
module github.com/mvanhorn/last30days-skill/mcp
go 1.22
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Mirrors skills/last30days/scripts/{last30days.py,lib/} into mcp/vendored/
# so the Go binary's embed.FS captures the engine at build time.
#
# Source of truth: skills/last30days/scripts/. Never edit mcp/vendored/ directly.
# Run before `go build` locally and in CI before `printing-press bundle`.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MCP_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
REPO_ROOT="$(cd "${MCP_DIR}/.." && pwd)"
ENGINE_SRC="${REPO_ROOT}/skills/last30days/scripts"
VENDORED="${MCP_DIR}/vendored"
if [ ! -f "${ENGINE_SRC}/last30days.py" ]; then
echo "sync-engine: ${ENGINE_SRC}/last30days.py not found" >&2
exit 1
fi
rm -rf "${VENDORED}"
mkdir -p "${VENDORED}"
# Copy the entry script and the lib/ tree (modules + lib/vendor/).
cp "${ENGINE_SRC}/last30days.py" "${VENDORED}/last30days.py"
cp -R "${ENGINE_SRC}/lib" "${VENDORED}/lib"
# Strip caches so the embed.FS stays deterministic.
find "${VENDORED}" -type d -name "__pycache__" -prune -exec rm -rf {} +
find "${VENDORED}" -type f -name "*.pyc" -delete
echo "sync-engine: vendored engine at ${VENDORED}"