mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-04 04:21:38 +00:00
c4d429d14c94de941ac761333cdac0a33895a05f
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
eb896e4469 |
feat(mcp): server-level instructions advertised in initialize handshake (TASK-971) (#355)
Adds a top-level `instructions` string to the MCP initialize response so agents know WHEN to reach for pad without having to guess from tool descriptions alone. The Svelte MCP server in the dogfooding session that triggered PLAN-969 does this; pad now does too. Implementation: - internal/mcp/instructions.md (new) — embedded source content. MCP-aware adaptation of skills/pad/SKILL.md's opener: what pad is, when to reach for it, the v0.2 tool catalog summary, resource cheatsheet, workspace resolution order, ref convention, update flow, conventions hint, and the four prompts. - internal/mcp/instructions.go (new) — //go:embed wrapper exposing the content as the Instructions package var. - internal/mcp/server.go — pass server.WithInstructions(Instructions) into NewMCPServer. Single source of truth: the same string ships in both the local stdio handshake AND PLAN-943's HTTPHandlerDispatcher (when remote /mcp mounts in TASK-950 it will reuse the same constant — no docs drift between local and remote surfaces). Test: TestServer_InitializeAdvertisesInstructions drives a real initialize round-trip and asserts the response's Instructions field equals the embedded source. Sanity-checks the embed didn't truncate. Parent: TASK-971 → PLAN-969. |
||
|
|
df8a3631e7 |
feat(mcp): v0.2 catalog scaffold + ToolSurfaceVersion + pad_meta tool (TASK-979) (#352)
* feat(mcp): v0.2 catalog scaffold + ToolSurfaceVersion + pad_meta tool (TASK-979) First commit of TASK-970's 3-stage rollout (PLAN-969). Introduces the hand-curated v0.2 catalog types (ToolDef, ActionFn, ActionEnv) and ships one tool — pad_meta — end-to-end. v0.1 cmdhelp-walk surface stays live alongside; subsequent commits (TASK-980, TASK-981) migrate the rest and flip v0.1 off. Architecture record: DOC-978. The fan-out registry sits ABOVE the dispatcher boundary — Dispatcher / route table are unchanged, so both ExecDispatcher (stdio) and HTTPHandlerDispatcher (HTTP) inherit the new shape for free. Changes: - internal/mcp/catalog.go (new) — ToolDef, ActionFn, ActionEnv, passThrough helper, RegisterCatalog, makeFanOutHandler, structured error helpers. - internal/mcp/catalog_meta.go (new) — pad_meta tool with three inline actions: server-info, version, tool-surface (full catalog dump for PLAN-943 docs generation). - internal/mcp/version.go — add ToolSurfaceVersion = "0.2" + matching experimentalToolSurfaceKey. Independent of CmdhelpVersion (cmdhelp owns CLI help-tree contract; ToolSurfaceVersion owns MCP catalog). - internal/mcp/meta.go — extend MetaPayload with ToolSurfaceVersion; experimentalCapabilities advertises both padCmdhelp + padToolSurface. - cmd/pad/mcp.go — call RegisterCatalog alongside Register so v0.2 surface is live. - Tests: catalog_test.go + catalog_meta_test.go (new); meta_test.go + server_test.go updated to assert the new field/capability. Parent: TASK-970 → PLAN-969. * fix(mcp): keep ToolSurfaceVersion at "0.1" until catalog is complete per Codex review (round 1) Codex P1: advertising tool_surface_version=0.2 while the user-visible surface is still predominantly v0.1 (cmdhelp walker active alongside, only pad_meta in the catalog) misleads consumers that pin against the handshake or pad://_meta/version. The padToolSurface namespace would suggest the full resource/action shape is available when in reality only pad_meta uses it. Delay the 0.1 → 0.2 bump to TASK-981 — the commit that retires the cmdhelp walker and ships the complete catalog. The constant stays declared so the surface contract is wired through the handshake + meta resource + pad_meta.tool-surface, the version string just truthfully reflects "still v0.1" until the catalog is complete. No test changes needed: every assertion uses the constant, not a literal "0.2". Parent: TASK-979 → TASK-970 → PLAN-969. * fix(mcp): scope pad_meta.tool-surface to v0.2 catalog only per Codex review (round 2) Codex P1: pad_meta.tool-surface description claimed "Full catalog dump: every tool" but during PLAN-969's parallel rollout, tools/list contains both the catalog (currently just pad_meta) AND the cmdhelp walker's ~85 verb tools. Calling the catalog dump "every tool" misleads consumers who expect a complete enumeration. Same spirit as round 1's fix: stop claiming what isn't true. The catalog dump is the v0.2 catalog by design — consumers wanting the complete advertised surface should read tools/list directly. Hand-mapping the walker output into the catalog dump would cost duplication for a surface that's about to disappear in TASK-981. Wire-level changes: - Tighten the action description in padMetaToolDescription to say "v0.2 catalog dump: every tool managed by the hand-curated catalog" and explicitly note tools/list is the source for the complete surface. - Add rollout_status field to the response payload: "in-progress" while ToolSurfaceVersion stays at "0.1", "complete" once TASK-981 bumps it. Lets consumers detect the rollout state programmatically. - Test asserts the new field tracks ToolSurfaceVersion. Parent: TASK-979 → TASK-970 → PLAN-969. * fix(mcp): include params in pad_meta.tool-surface dump per Codex review (round 3) Codex P1: tool description claimed the dump includes each tool's "input schema" but the payload only emitted name/description/workspace/ actions[]. Misleading for docs generators (TASK-957) that would build getpad.dev/docs/mcp from this canonical source. Going with the substantive fix rather than just trimming the description: include a synthesized params[] per tool entry. Mirrors what consumers see in tools/list — `action` (always required, enum of declared action names), `workspace` (when ToolDef.Schema.Workspace=true), and per-tool ParamDefs. Synthesizing `action` and `workspace` rather than copying them from ToolDef makes the dump self-contained: a docs generator doesn't need to reproduce buildToolFromDef's implicit-param logic separately. Test asserts each catalog entry has params[] starting with `action` (enum length matches action handler count) and the right total length based on Schema.Workspace + Schema.Params. Parent: TASK-979 → TASK-970 → PLAN-969. |
||
|
|
e05ea07d62 |
fix(docs): use canonical wire path capabilities.experimental.padCmdhelp (#342)
Codex caught the same accuracy issue on pad-web that exists in five
spots in this repo: prose described the handshake location as
"serverCapabilities.experimental.padCmdhelp", but per the MCP spec
the InitializeResult shape is
{ result: { capabilities: { experimental: { ... } } } }
There's no `serverCapabilities` field on the wire — `ServerCapabilities`
is the Go-side struct type name in mcp-go; the JSON tag is
`capabilities`. Anyone copying the path out of our docs to navigate
a real JSON-RPC envelope was getting the wrong key.
Updated to `capabilities.experimental.padCmdhelp` (or the fully
qualified `result.capabilities.experimental.padCmdhelp` where the
JSON-RPC envelope context wasn't otherwise obvious) in:
- README.md — public-facing prose
- CLAUDE.md — agent-facing prose
- internal/mcp/version.go — discovery-surfaces doc comment + the
experimentalCapabilityKey doc comment
- internal/mcp/server.go — comment near WithExperimental
- internal/mcp/meta.go — experimentalCapabilities() doc + the wire
shape example (now wrapped under `result` for accuracy)
- internal/mcp/server_test.go — test docstring + failure message
- cmd/pad/mcp.go — comment near RegisterMeta
The Go type `serverCapabilities` in `internal/server/handlers_capabilities.go`
is unrelated (it's the response shape for `GET /api/v1/server/capabilities`)
and stays as-is.
No code/behaviour changes; pure prose accuracy fix. `make check` clean.
Companion fix to pad-web PR #42, which Codex flagged the same issue on.
|
||
|
|
2d98f2a170 |
feat(mcp): advertise cmdhelp_version stability tier in handshake (TASK-963) (#340)
* feat(mcp): advertise cmdhelp_version stability tier in handshake (TASK-963)
External agents (Cursor, Claude Desktop, the future Pad Cloud remote MCP
in PLAN-943) depend on tool names, argument shapes, and resource URIs
being stable across pad releases. Without an explicit contract, any
future surface change breaks consumers silently.
This commit ships the contract on two complementary surfaces:
- serverCapabilities.experimental.padCmdhelp in the initialize handshake
— namespaced map carrying {version, tool_surface_stable}, discoverable
in one round-trip.
- pad://_meta/version static resource — full JSON document with
{pad_version, cmdhelp_version, tool_surface_stable, mcp_protocol_version}
for clients that prefer reading a typed payload.
CmdhelpVersion is pinned at "0.1" — the initial cmdhelp-derived surface
shipped in PLAN-942. Bump the major when tool names / arg shapes /
resource URIs change incompatibly.
Tests:
- TestServer_InitializeHandshake extended to assert the experimental
capability shape on the wire (not just the existence of the field).
- TestBuildMetaPayload_* lock the payload field names + fallback
behaviour.
- TestRegisterMeta_ResourceRoundTrip drives the resource through the
real HandleMessage path so a regression in the dispatcher would
surface as a test failure.
Docs:
- README's MCP section briefly mentions the contract surfaces.
- CLAUDE.md's MCP section gets a stability-contract paragraph + the new
resource URI.
- Public docs at getpad.dev/mcp/local will need a follow-up PR in the
pad-web repo (per CONVE-159) — captured at the end of TASK-963.
Parent: PLAN-942.
* fix(mcp): source MCP protocol version from mcp-go LATEST_PROTOCOL_VERSION per Codex review (round 1)
Codex caught: the local MCPProtocolVersion constant was pinned at
"2024-11-05", but mcp-go@v0.50.0 negotiates "2025-11-25" for clients
that request mcp.LATEST_PROTOCOL_VERSION. The meta resource was
therefore reporting a protocol revision newer than what the server
actually speaks, which defeats the field's purpose for feature
detection (e.g. RFC 8707 Resource Indicators land in 2025-11-25).
Drop the local constant and read mcp.LATEST_PROTOCOL_VERSION at
BuildMetaPayload time so the value tracks whatever revision the
linked library will negotiate. The handshake's serverInfo.version
already does this implicitly via NewMCPServer; making the meta
resource follow the same source-of-truth keeps both surfaces in
lockstep across mcp-go upgrades.
Test updated to assert against mcp.LATEST_PROTOCOL_VERSION instead of
the removed constant, plus an "empty-string" guard in case a future
library refactor unsets the constant.
Parent: PLAN-942.
|
||
|
|
9905a83134 |
feat(mcp): pad mcp serve skeleton on stdio (TASK-944) (#333)
Stand up internal/mcp + the cobra `pad mcp serve` subcommand. v1 is
handshake-only — the server completes initialize and stays alive over
stdio, advertising tool capability with an empty registry. TASK-945
fills that registry from `pad help --format json`.
- New internal/mcp package wraps mark3labs/mcp-go's stdio transport;
graceful shutdown on EOF / SIGINT / SIGTERM / ctx-cancel.
- New cmd/pad/mcp.go registers `pad mcp` as a top-level cobra group
with the `serve` subcommand wired to internal/mcp.NewServer.
- 4 unit tests: NewServer construction, real initialize round-trip
(asserts serverInfo.name + version), fallback version locked,
graceful shutdown on ctx-cancel.
Live smoke: `echo '<initialize>' | pad mcp serve` returns
`serverInfo:{name:"pad-mcp",version:...}` with `tools:{listChanged:true}`.
cmdhelp emits the new command tree at `pad help mcp serve --format json`.
Parent: PLAN-942.
|