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:
@@ -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/
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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.
|
||||||
@@ -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.
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/mvanhorn/last30days-skill/mcp
|
||||||
|
|
||||||
|
go 1.22
|
||||||
Executable
+32
@@ -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}"
|
||||||
Reference in New Issue
Block a user