Repository navigation
Description
Relocated from dezren39/darwin-nix#114 on 2026-10-28 (placement audit): mcpx's single source lives in developing-today/code (pkgs/mcpx); re-home tracked at #309. Original body below; issue references inside it are historical (dezren39/nix numbering).
Parent: #176
Summary
Four related asks: compose new tools out of existing ones, add tools to a server that does not have them, turn an arbitrary executable into a server by generating its spec, and make a restricted renamed view of a server. The user's framing is "generate" for all four — a model produces them.
The finding of this issue is that three of the four are better as declared, deterministic features, with generation as an optional author-time convenience on top, and that mcpx is roughly 70% of the way there already: aliasOf + tool filtering + prelude (aliases, docs/story.md §"Profiles and aliases"), internal/adapter (CLI programs as servers), internal/openapi + mcpx api --spec (OpenAPI documents as servers). What is missing is small and specific: pinned arguments, tool renaming, cross-server composition, and script-backed tools.
The distinction that matters: a generated artefact is a file a human reviews and checks in; a runtime behaviour is a thing that must be correct every time. Generation belongs to the first and never to the second.
Original notes
- mcp-owned opencode api support
- generate OpenAPI.fromSpec for a binary or script or any executable/whatever and add it as an mcp, save the openapi json for reuse by hash or similarity
- generate new mcp commands out of existing 1 or more
- generate new mcp commands that trigger its own prompts/scripts/binaries
- generate new x_commands for an mcp and add them into the given mcp
- doesn't have to just be merging transforming filtering limiting existing
- can extract the creds pull the api and add endpoints from sdk missing in mcp using the sdk descriptions
- please make an alias for the tailscaleMcp except it should not require auth it should accept the creds i already used to connect to it and the only skill it should provide is listTailnet and listHostnames
Current state (what mcpx does today, with file refs)
Aliases already do most of the tailscale request. From docs/story.md §"Profiles and aliases" and internal/config/config.go:148-152:
"tailscale-peek": {
"aliasOf": "tailscale",
"mcpx": {
"tools": ["list_devices", "list_tailnets"],
"description": "read-only view of the same tailnet"
}
}An alias is "a second view — its own namespace, tool subset, prelude and description — over the same command". Tool filtering is not part of pool identity, "because filtering is presentation", so the alias shares the target's running process and therefore its already-established credentials — which is precisely the note's "it should accept the creds i already used to connect to it". Filtering is applied by visibleTools (internal/daemon/registry.go:183) against Resolved.Tools/ExcludeTools. Alias chains are rejected.
What the alias mechanism cannot do, and the note asks for:
| gap | detail |
|---|---|
| rename a tool | the note wants listTailnet and listHostnames; the view exposes whatever the server named them. Tools/ExcludeTools select, never rename. |
| pin or default an argument | no way to say "this view always passes readonly: true" or "drop the tailnet parameter from the schema and always send -". docs/proposals.md §"Per-instance argument templating" proposes templating argv, not tool arguments — different layer. (An adapter parameter already has a Default, internal/adapter/adapter.go:86-87; a view over an MCP server has nothing.) |
| compose across servers | a view is over exactly one target. |
| add a tool that the server does not have | nothing can inject a tool into a namespace. |
| narrow a schema | no way to remove or constrain a property in the exposed inputSchema. |
Executables as servers already exists, declaratively. internal/adapter turns a command-line program into a server from a JSON declaration — paths.adapters, Spec{Name, Command, Args, Env, Dir, Description, Instructions, Timeout, Tools[]}, each ToolSpec{Name, Args, Params[], Stdin, JSON, Timeout} with Param{Name, Type, Required, Flag, Repeat, Default, Enum}. Its tests encode the sharp edges: a boolean becomes the flag's presence not --loud true, a repeated flag is sent once per value, a missing required parameter is refused before the process starts. Its package doc states the boundary explicitly: "This is deliberately not a general shell escape. A tool here is a named subcommand with declared parameters, so a model cannot invent a command line, and what is reachable is exactly what somebody wrote down." Two limits at 05c78b2: adapter tools are loose MCP tools, not namespaces — absent from mcpx ls, the generated TypeScript and scripts (#83, #102) — and mcpx adapter today offers only list, check and call (internal/cli/adapter.go).
OpenAPI documents as servers already exists. internal/openapi + APISpec{Name, Spec, BaseURL, Include, Exclude, Methods, IncludeDeprecated, Headers, Description} + paths.apis + mcpx api tools|call --spec <path-or-url>. Headers expand ${VAR} from the environment "so a declaration can be checked in and a token cannot" (internal/cli/openapi_tools.go:64-68).
Scripts as reusable units already exist. Recipes (#41): a script on the search path declaring @param holes in a header comment, matched by a deterministic scorer, runnable via POST /v1/recipes/{name}/run. What a recipe is not is a tool: it does not appear in tools/list, has no inputSchema, and is not callable as namespace.tool.
MCP tools are generated from the ops table (internal/api/ops*.go), and GET /v1/openapi.json is generated from the same declarations — the precedent that one declaration should drive every surface.
Approaches
Approach A — least recommended: a model generates tools at runtime
mcpx is asked for a tool it does not have; a model composes one on the fly from the catalogue and it becomes callable.
Why not:
- A tool is an interface, and an interface that changes shape is not one. MCP clients cache
tools/list;2026-07-28addsttlMs/cacheScopespecifically to make that caching reliable, and asks servers to return tools in deterministic order for prompt-cache hits. A catalogue that varies run to run breaks all of it. - It defeats the reason mcpx exists. The pitch is that tool schemas stay out of the model's context. Generating a tool requires sending schemas to a model — on a path that was supposed to avoid exactly that.
internal/adapter's stated boundary is the thing being given up. "A model cannot invent a command line" is the property that makes adapters safe. Runtime generation is that property removed, reintroduced as a feature.- Unreviewable and unversionable. Nobody can diff it, check it in, or say why it changed.
Approach B — middle: extend views to be real transforms, declared in config
Generalise aliasOf from "a filtered view of one server" to a declared tool view that can rename, pin, narrow, and compose:
"tailscale-peek": {
"aliasOf": "tailscale",
"mcpx": {
"description": "read-only tailnet listing",
"toolViews": {
"listTailnet": { "from": "list_tailnets" },
"listHostnames": { "from": "list_devices",
"pin": { "fields": ["hostname"] },
"hide": ["tailnet"],
"description": "hostnames on the current tailnet" }
}
}
}-
fromrenames;pinsupplies fixed arguments the caller cannot set;hideremoves pinned properties from the exposedinputSchemaso the tool looks like what it is;descriptionoverrides. Selection (tools/excludeTools) stays as it is and atoolViewsmap implies the allowlist. -
Composition across servers needs one more thing: a view whose
fromis a fully-qualifiedserver.toolrather than a bare name, and a server entry with noaliasOfat all — a virtual namespace assembled from several targets.Registry.viewsis alreadymap[string]*config.Resolvedkeyed independently of pools (internal/daemon/registry.go:41-45, "pools may be shared between names; views never are"), so this is a natural extension rather than a new concept. Namespaces and collision rules are chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83's (Phase 3: sync, blob gate, and relays #181 collision 4). chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83's tool-source interface defines what a namespace is and what happens when two sources claim one name; virtual namespaces, views and script-backed tools here are built on those rules and do not define their own. The shapes in this section are input to chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83. -
Sequencing two tools into one ("out of existing 1 or more" where more than one must run) is not a schema transform — it is a script. Which is the next item.
-
Script-backed tools are the highest-value missing piece and the smallest: let a config declare a script as a tool.
"ops": { "scripts": { "staleIssues": { "file": "close-stale.ts", "description": "...", "params": "auto" } } }
The script's
@paramheader already declares its holes with types — the same header recipes use — soinputSchemagenerates from it with no new authoring format. This single feature covers "generate new mcp commands that trigger its own prompts/scripts/binaries" entirely: a script can call several tools, shell out, run a prompt, or invoke a binary, and it appears as one ordinary tool. It also promotes recipes from a side channel to first-class, which they should be. This is the same feature as chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83's first ship step ("recipes as tools, since the schemas already exist"), so it lands as a chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83 tool source; the config spelling above is a proposal for that, not a second mechanism. -
Scope and profiles apply unchanged, so a view can be
default: falseand pulled in by--profile.
This is deterministic, diffable, reviewable, testable, cacheable, and it is what the runtime should be built on regardless of whether anything ever generates it. It also answers the tailscale request exactly and completely.
The cost is authoring: someone has to write the JSON, and for the SDK-mining case ("extract the creds pull the api and add endpoints from sdk missing in mcp using the sdk descriptions") that is a lot of JSON. Which is where generation earns its place — but as an author-time tool, not a runtime.
Approach C — recommended: B as the runtime, plus generators that emit declarations
Build Approach B. Then add generators whose only output is a file in one of the formats mcpx already consumes — an adapter Spec, an APISpec, an OpenAPI document, or a toolViews block. The generator is a mcpx subcommand a human runs; the daemon at runtime reads only declarations, exactly as it does today.
mcpx adapter generate <binary> # --help scraping + a model -> adapter Spec JSON (beside today's list/check/call)
mcpx api generate <binary|script> # -> an OpenAPI document
mcpx view generate <server> "<ask>" # -> a toolViews block
Each prints to stdout or writes to a path, is reviewed, and is checked in. The runtime is unchanged and cannot be surprised.
OpenAPI.fromSpec for an arbitrary executable, concretely. The deterministic first pass is substantial and should come first: run --help, help, -h, --help=full; parse the common conventions (a usage line, an indented flag block, subcommand tables); many modern CLIs also expose --json/completion output, and Cobra/clap/argparse produce highly regular help text. That gets a usable adapter Spec for a large fraction of programs with no model at all, and a model's job becomes filling in descriptions and types the help text left ambiguous — which is exactly the job a model is good at and the one where being wrong costs a bad description, not a wrong command line.
On the note's "save the openapi json for reuse by hash or similarity": hash, yes; similarity, no. Cache on the binary's content hash plus its --version output. A content hash is exact and a stale entry is impossible. Similarity matching on binaries ("this looks like a tool I have a spec for") would hand one program another program's command-line interface, which fails by constructing a plausible, wrong invocation — the worst failure mode available. If a similarity notion is wanted at all it should surface as a suggestion to a human ("this looks like rg 14.x, reuse that spec?"), never as an automatic resolution. Note also that the natural intermediate here is the adapter Spec, not OpenAPI: a local executable is not an HTTP service, and internal/adapter already models argv, flags, stdin and JSON output, which OpenAPI does not. Generate the adapter spec; generate OpenAPI only for things that really are HTTP services.
Adding endpoints an MCP server omits, from its SDK. This is the most ambitious item and the most valuable when it lands, because the common complaint about vendor MCP servers is that they expose a fraction of their own API. The route with the best ratio: many vendors publish an OpenAPI document for the service the MCP server wraps, and mcpx can already turn one of those into tools (mcpx api --spec). So the deterministic path is: point APISpec at the vendor's published document, Include the operations the MCP server lacks, expand the auth header from the environment — and merge that into the same namespace with a virtual view. No model, no SDK parsing, no credential extraction. Mining an SDK's source for undocumented endpoints is a much larger and much more fragile project, and should only be considered where no document exists. "Extract the creds" is out of scope here — reusing a credential means naming an environment variable in the declaration, which APISpec.Headers already supports with ${VAR} expansion; anything that reads a credential out of a running server's process is a security design and deferred.
On the nested "doesn't have to just be merging transforming filtering limiting existing" — agreed, and that is what script-backed tools are for. Once a script can be a tool, "new" has no ceiling: a tool can call three servers, run a binary, transform the result and return something none of its inputs could produce. The declarative view layer handles the cheap 80% (rename, pin, hide, select, compose schemas) and scripts handle everything else, which is a cleaner split than trying to make a declarative transform language Turing-complete.
Recommended because the runtime stays declarative and reviewable, because every generated artefact lands in a format that already has a loader and a test suite, because the highest-value single feature (script-backed tools) needs no model at all, and because it answers the user's concrete request — the tailscale alias — today, in config, with one small addition to a mechanism that already exists.
What the tailscale request needs, specifically
| requirement | status |
|---|---|
| a second namespace over the same server | exists (aliasOf) |
| reuse the credentials already in use | exists — the alias shares the pool, hence the process, hence its auth; also Headers ${VAR} expansion for the HTTP case |
| expose only two skills | exists (mcpx.tools allowlist) |
name them listTailnet and listHostnames |
missing — needs toolViews.from |
| "should not require auth" | ambiguous: reusing the target's session is what the alias does; genuinely removing an auth requirement is deferred |
So this is roughly a one-field change away from working. Worth doing first, on its own, as proof the view layer is the right shape.
Open questions
- Do renamed tools break anything that assumes a tool name is the server's name?
codegen.ToolFuncName,catalog-history.jsonkeying, diagnostics, andinternal/diagnose's namespace filter all key on names — the view's name must be what the caller sees and the target's name what history records, and those must not be confused. - Should
pinbe invisible or merely defaulted? Invisible (hide) is what the tailscale case wants; defaulted-but-overridable is friendlier. Probably both, as separate fields. - Virtual namespaces and profiles: does a virtual view belong to the profiles of its targets, or declare its own?
- Where do generated declarations live by default —
paths.adapters/paths.apistargets, a state directory, or stdout only? Stdout only is safest; a--writeflag is the convenience. - Does a script-backed tool run through
POST /v1/execwith the caller'sExecOptions, or with fixed options from its declaration? Fixed, probably, or a tool's behaviour depends on who called it. - Should
tools/listmark a view-derived tool as such in_meta, so a client can tell it is not the server's own? - How does a script-backed tool declare
destructiveHint/readOnlyHint? It must, or the confirmation policy has nothing to work with. - Is there a path to contributing generated adapter specs back — a shared repository of specs by binary hash? Useful, and a distribution question rather than a code one.
Ease · Impact · Related
Ease L overall; the tailscale-unblocking toolViews.from/pin/hide is S–M, script-backed tools M, virtual cross-server namespaces M–L, spec generation L · Impact high — it turns mcpx from a router into a place where a personal tool surface is composed, and script-backed tools alone make recipes first-class.
Depends on / related: #83 (owns namespaces, collision rules and the tool-source interface this builds on — #181 collision 4; its step 1 is script-backed tools and its step 5 generated declarations), #102 (an adapted binary is not script-callable — in flight), #7 (launcher placeholders — same @ substitution family), #41 (closed, fixed in #58: recipes and their @param headers are the input format for script-backed tools), #40 (closed, fixed in #57: artifacts, for generator output), #5 (config chain — views must layer), #76/#77 (ops table and protocol; _meta marking and annotation plumbing), docs/proposals.md §"Protocol adapters, including OpenAPI" and §"Per-instance argument templating". Siblings: #110 (generators' model), #115 (the tailscale/Dropbox/Drive/Outlook servers this would view), #111 (shared schema-validation code).
Security/auth deferred; see tracker.
Activity
developing-today commentedon Oct 28, 2026
CODE-859
dezren39 commentedon Oct 28, 2026
History carried over from dezren39/darwin-nix#114 (verbatim, oldest first):
@dezren39 · 2026-09-30T07:21:53Z
Integration pass. Placed in the DAG rooted at #181.
d956689tod460fcc#109 Bump build/buck/preludes/buck2-prelude fromd956689to52604b1#110 Bump checkmarx/ast-github-action from 2.0.19 to 2.0.23 #111 Update module gopkg.in/go-jose/go-jose.v2 to v2.6.3 [SECURITY] - autoclosed #112 Update module github.com/jackc/pgx/v5 to v5.5.4 [SECURITY] - autoclosed #113 Update github.com/charmbracelet/promwish digest to 6c16e8f - autoclosed #115@dezren39 · 2026-09-30T07:27:58Z
Integration pass -- cross-theme collision. Surfaced only when the themes were put side by side; the authors of these issues could not see each other's work. Recorded at the root in #181.
Namespacing and collision rules are being designed twice
#83's tool-source interface and #114's cross-server namespaces, script-backed tools and generated declarations are substantially the same problem, in two different themes (#173 and #176). Two namespace schemes that must later be merged.
Also on: #83. Nobody currently owns this.
@dezren39 · 2026-09-30T11:06:10Z
Collision ownership (issues pass, 2026-09-30, at 05c78b2). #181 listed these cross-theme collisions with no owner. Each now has one:
Where this issue is the owner, the decision is made here; where it is not, it adopts the owner's decision rather than making its own.
@dezren39 · 2026-09-30T11:57:48Z
Issues pass (2026-09-30, at 05c78b2).
Parent: #176.d956689to36464cf#83's. The body now says virtual namespaces, views and script-backed tools build on chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83's tool-source rules and do not define their own. It also notes that script-backed tools are chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83's first ship step (recipes as tools) and that its fifth step overlaps the generators. The design text is kept as input to chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83.Paramalready hasDefaultandEnum(internal/adapter/adapter.go:86-89); a view over an MCP server has nothing like it.mcpx ls, codegen and scripts (chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83, Bump build/buck/preludes/buck2-prelude fromd956689tof12c8d1#102).mcpx adaptertoday islist/check/callonly, andadapter generatewould sit beside them.Related:adds chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to36464cf#83 and Bump build/buck/preludes/buck2-prelude fromd956689tof12c8d1#102, marks Bump openssl from 0.10.54 to 0.10.55 in /sources/pavex/examples/realworld #40 and Bump build/buck/preludes/buck2-prelude fromd956689to6f75473#41 as closed (fixed in chore(deps): bump build/buck/preludes/buck2-prelude fromd956689to677e9eb#57 and chore(deps): bump rustix from 0.38.3 to 0.38.21 in /build/nix/setup #58), and names siblings by number. Labeldesignadded. Ease/Impact unchanged (L / high).@dezren39 · 2026-09-30T16:58:21Z
Decided (SURFACES, 0002-autonomy-dial, merged in #228). Generators are
proposeby construction: they print a declaration and a human writes it into config. That is not a setting and cannot be raised;--write <path>is the human's own act. No change to approach C. Namespaces and collision rules stay #83's (#181 collision 4).@dezren39 · 2026-10-28T22:31:07Z
Triage verdict (task 2159, repo-health-nix-pilot): CONFIRMED + RELOCATED — the alias/filtering foundation is intact in the new home, and all five specific gaps this issue names are still gaps. Implementation routes in developing-today/code; no fix packet in this repo.
Verified against current main on both sides (nix
224c7b738e88c7a8e5d406987a7d88257e229db2, coded2cb60fe8e08cd6fee149b930187b610299c1fa7):enhancement,design— no hard-stop labels. Parent tracker Nix Playwright E2E suite fails after vendoring dependencies #176 is OPEN.pkgs/mcpxat HEAD; the extraction plan (planning/plans/mcpx-extraction.md, steps 4–5, lab-ops-hub container crawler accepts inet_aton IPv4 spellings (127.1, 2130706433, 0x7f.1) — loopback SSRF bypass in validate_crawl_url #468) records the build switch and deletion done 2026-10-19, and this repo now only builds mcpx from the pinned code rev.aliasOf(pkgs/mcpx/internal/config/config.go:177-181), per-view allow/deny viaTools/ExtraIncludeTools/ExcludeTools(config.go:134-141), applied byvisibleTools(internal/daemon/registry.go:227-228), and a per-viewNamespaceoverride (config.go:102-103). Hide and namespace-rename of a whole view therefore work, exactly as the issue's current-state section said.internal/configorinternal/daemon:Tools/ExcludeToolsselect only; there is no rename map on a view.Param.Defaultthe issue cited is a different layer and still the only one).AliasOfnames one server).inputSchema.Route: no
small_fixpacket in dezren39/nix — this repo holds no mcpx source to fix. The gaps are small and specific, in the issue's own assessment, and belong with the source in developing-today/code, referencing #114, via the #309 relocation pass; per the cross-repo rule, do not re-file it there. #114 stays open on the nix side until implemented there or transferred.dezren39 commentedon Oct 29, 2026
🤖 Agent note · picked up
dezren39 commentedon Oct 29, 2026
🤖 Agent note · done (triage)
Triage verdict
Dedupe. The four asks split across existing work more than the issue (written pre-relocation) could know:
@paramschemas. Same feature this issue calls "#83's first ship step" — #83 relocated here as #1875. Not re-enqueued.--helpscraping rejected in the parent.APISpec.Include. Credential extraction stays out of scope (this issue agrees).from=server.tool, views with noaliasOf)toolViewsblocks (mcpx view generate)Scope confirmed on current main (
c58507a, 2026-10-29).aliasOfexists (internal/config/config.go:177-181, resolved :556) and aliases share the target's pool/process, so credential reuse already works as the tailscale note asks.visibleTools(internal/daemon/registry.go:227) applies allow/deny lists only. Grep acrosspkgs/mcpx/internal+docs: notoolViews, no rename, no argument pinning for views. The gap table in this issue is accurate as of today.Enqueued — task 3230 (slice 1, small_fix):
toolViewson alias views —from(rename),pin(fixed args the caller cannot set),hide(pinned properties removed from the exposedinputSchema),descriptionoverride; atoolViewsmap implies the allowlist; calls invoke the target with pinned args merged while history/diagnostics keep the target's real name; config validation rejects unknown targets, duplicate view names, and pins of non-schema arguments. Defining test is this issue's tailscale shape (view exposing exactlylistTailnet+listHostnames, one property pinned + hidden). Acceptance criteria are in the packet; the PR must reference, not close, this issue.Remaining on this issue (slice 2, not enqueued): cross-server virtual namespaces, gated on #1875's collision rules landing with its splits (#2117/#2118 in flight). Once slice 1 merges, slice 2 is a clean follow-up packet against this issue.
401 remaining items
dezren39 commentedon Nov 2, 2026
agent-note:v1 — resumed
Agent: repo-worker-code (openchamber scheduled lane)
Task: repo-health-code-pilot task 5609 (pr_shepherd, priority 30)
Started: 2026-11-02T09:43Z
Plan: verify the canonical PR #2976 at current head, audit every unresolved Codex finding, inspect CI failures, and merge only if findings are dispositioned and required checks are green.
Fresh state: #1933 open; PR #2976 open against main at ce1d517 on canonical branch queue/3230-1933-toolviews-slice1. Current run 41366817770 has lint and changed-tests stress failures; other reported checks pass. PR is the canonical task-owned agent PR per packet (the shared fleet account author is not a Drew-owned restriction).
dezren39 commentedon Nov 2, 2026
agent-note:v1 — parked
Agent: repo-worker-code (openchamber scheduled lane)
Task: repo-health-code-pilot task 5609 (pr_shepherd, priority 30)
Reason: PR #2976 is not merge-ready at head ce1d517. Current CI run 41366817770 fails lint and the changed-tests stress gate: the logs report conformance mocks still return []string from Backend.Complete where the merged-base interface requires mcpserver.Completion. Six current-head Codex findings require a complete disposition audit: #4437521105, #4437521108, #4437521110, #4437521114, #4437994622, #4437994629.
Resume condition: recreate a task worktree from the canonical remote PR branch (the recorded local path is absent), sync current main, audit/reply to all current findings, fix the CI failure, verify targeted tests and green checks, then merge only under the standing criteria. Keep #1933 open for slice 2.
Queue: parked for 20 minutes; issue and PR labels restored to queue/parked + status/parked; work/assigned retained.
dezren39 commentedon Nov 2, 2026
🤖 Agent note · parked
queue/3230-1933-toolviews-slice1, head ce1d517) but not merge-ready; the remaining work exceeds this shift's remaining budget and the laptop has no build window (load ~92–102 on 16 cores, sustained).internal/conformancetest mocks implementingBackend.Completeas []string where current main's API requires mcpserver.Completion (branch staleness, not this PR's files). Docs/plugin/mcpx-docs checks pass.~/git/fleet/5609-1933-toolviewsdoes not currently exist — recreate it from the remote PR branch.queue/3230-1933-toolviews-slice1, sync current main, fix the conformance mock signatures, disposition each Codex finding (fix or reply), re-run targeted config/daemon tests (-race -shuffle=on -count=5), merge when green. Keep mcpx: tool views and composed tool sets — rename/pin/hide, cross-server namespaces, script-backed tools, and generators that emit declarations #1933 OPEN for slice 2.dezren39 commentedon Nov 2, 2026
🤖 Agent note · parked (shepherd prep done; needs a dedicated merge window)
queue/3230-1933-toolviews-slice1(fleet PR for task 3230 — the old Drew-owned block was the shared-account misread, already corrected in the packet).pkgs/mcpx/internal/conformance/features_test.golines 308 and 389: thefailingReadsmock still implements the oldComplete(context.Context, json.RawMessage) ([]string, error)signature; main now wants(mcpserver.Completion, error). Fix those two mock sites after the main sync.~/git/fleet/5609(laptop) on the PR branch; merging current origin/main conflicts in exactly 3 files / 9 hunks — daemon/input_required.go (2), daemon/registry.go (5), daemon/routes_proto.go (2). First routes_proto hunk is semantic: main refactoredresolveAndGuardto return a resolved struct while the PR returns (key, effTool, effArgs) for view-projected calls — resolve by intent, not by union. The merge was aborted cleanly; the remote branch is untouched at ce1d517.dezren39 commentedon Nov 2, 2026
agent-note:v1 — task 5609 picked up by repo-worker-code (lane D) 2026-11-02 ~15:38Z to shepherd PR #2976 (slice 1). Fresh state: PR #2976 OPEN at ce1d517 (unchanged), issue #1933 OPEN, no hard-stop labels. Plan from the parked prep: merge current main in the laptop worktree (3 conflicted files), fix the conformance Complete-signature root cause behind the red jobs, disposition the latest Codex round, targeted tests, merge when green; issue #1933 stays open for slice 2.
dezren39 commentedon Nov 2, 2026
agent-note:v1 — task 5609 (lane D) progress 2026-11-02 ~15:55Z: the merge half of the shepherd window is DONE. Merged origin/main into PR #2976 (head now 92a21ec): 4 conflicted files resolved — config.go (ToolViews validation kept alongside mains namespace identifier check), and the resolveAndGuard refactor composed across daemon/registry.go, input_required.go, routes_proto.go (new signature returns ResolvedScope plus the views effective tool/args; policies and the destructive floor see the effective identity, the pool gets rs + effective tool/args). Laptop verification on the merged tree: go build clean; internal/config and internal/daemon suites pass (daemon 62s). Conformance suite: 4 failures (TestAuthSplit, TestMatrix, TestMessagesClient, TestUtilitiesServer) reproduce identically on clean main — pre-existing, and the preps named root cause (features_test.go Complete signature) is gone. Remaining before merge: 6 unresolved Codex P2 threads (schema-projection edge cases in argumentrules.go / registry.go from the 2026-11-01T21:56Z and 2026-11-02T00:27Z rounds, no disposition replies yet) and CI on the new head. Task 5609 parked; resume = disposition those 6 threads, CI green, merge PR #2976, keep issue #1933 open for slice 2.
dezren39 commentedon Nov 3, 2026
agent-note:v1
opencode; the claimant's bound session owns the terminal verbs — expected completion as fixed_merged for slice 1. Issue mcpx: tool views and composed tool sets — rename/pin/hide, cross-server namespaces, script-backed tools, and generators that emit declarations #1933 stays open: slice 2 (cross-server virtual namespaces) remains on it per the packet.dezren39 commentedon Nov 3, 2026
agent-note:v1 — state: handed off — queue task 3230 launched in bound OpenCode session ses_e5e5f402149ffed9rlYheEb6Kx by opencode-claimant.
dezren39 commentedon Nov 3, 2026
Slice 1 complete: PR #2976 (toolViews rename/pin/hide on alias views) merged as 4ab08c0. Verified: merge commit on main, full `go test ./internal/daemon ./internal/config -count=1` PASS. Issue stays open for slice 2 (cross-server virtual namespaces) per packet acceptance.
dezren39 commentedon Nov 3, 2026
agent-note:v1
state: parked (scoped, not started — needs a full implementation slot, not a 15-minute tail)
Scope note for the next claim. Claimed as
small_fix(task 8020) but the remaining work is #1933 slice 3: script-backed tool views — the one aspect of the four in the issue body with no declared path at all. Slice 1 (rename/pin/hide on alias views) is merged (PR #2976,4ab08c06); nothing is open for it. I am stopping rather than half-landing a config-surface change; a resume brief is below so the next claim starts at the code, not at the issue.The gap, with refs (main @
4c75cc808)config.ToolView(pkgs/mcpx/internal/config/config.go:181) hasFrom,Pin,Hide,Description.Fromis mandatory in practice, so a view can only rename/arg-pin a tool that already exists on an aliased upstream server.viewTools(pkgs/mcpx/internal/daemon/registry.go:~455) looks upbyName[tv.From]and silently skips a missing target ("load-time validation names this"). There is no branch that manufactures a tool.ruleToolName(registry.go:~425) returnstv.From, andeffectiveViewSchema(~438) keys argument rules off it. Both assume a real upstream tool name exists.Resolved.VisibleTool(config.go:605) callsr.ExcludeTools.Match(tv.From)andr.PassesPreconditions(tv.From, nil)— both meaningless for a view with no upstream tool.adapter.Spec/adapter.ToolSpec/adapter.ParamwithToolSpec.Schema()(pkgs/mcpx/internal/adapter/adapter.go:69,88,238) andSpec.Call(:283). That is exactly "a declared local command exposing typed tools".Proposed slice (for the implementer to confirm)
ToolViewwith a command-backed form:command,args,env,dir,timeoutand aparams/stdin/jsonshape borrowed fromadapter.ToolSpec, so one view can be a script with typed arguments.from|command; a command view cannot declarepinof upstream properties;hide/pinkeep their meaning forfromviews only. Name the error at the config boundary (same shape as existingToolViewsvalidation).viewToolsbefore thebyNamelookup, producingmcpclient.ToolwithToolSpec.Schema(), and route calls in the daemon's call path toadapter.Spec.Call, not the upstream client.ruleToolNameandeffectiveViewSchemahandle a view with noFrom: rules key off the view name, andVisibleToolskips the upstream-onlyExcludeTools/PassesPreconditionschecks for command views.pkgs/mcpx/internal/daemon/toolviews_test.goalready has the table-driven view cases; add (a) command view lists with typed schema, (b) call executes and returns output, (c)from+commandtogether is a load error, (d)pinon a command view is a load error, (e) name collision with an upstream tool.Open questions to settle before coding
viewscache at all, or should it hang off the same registry the adapter tools use? The currentviewToolssignature takesall []mcpclient.Toolfrom one upstream — a script-backed view has no upstream to be cached beside.mcpx lslist it (the issue's "first-class namespace" ask) and does generated TypeScript include it? Slice 1 got listing; command views need the same treatment or the feature is again second-class.Resume condition: a claim with a full lease. Nothing is half-done — no branch, no worktree, no local edits, so this is a clean start. Queue task 8020 parked.
Found via: triage packet for #1933 (coverage pass 2026-11-03)
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done
ToolViewinpkgs/mcpx/internal/config/config.go(commented "(mcpx: tool views and composed tool sets — rename/pin/hide, cross-server namespaces, script-backed tools, and generators that emit declarations #1933 slice 1)") already provides rename (from), pinned arguments (pin, with exact-number decoding perinternal/config/parse_pin_test.go),hide, and description override over an aliased server (aliasOf, config.go:222);internal/adapterandinternal/openapialso exist, matching the issue's survey. Still missing from the issue's list: script-backed tools (a ToolView's only backing today is an upstream tool viafrom;Extras.Scriptis snippet settings, not a tool backing) and cross-server composition (views are per-alias, one underlying server).dezren39 commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 30 (priority/none). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03
dezren39 commentedon Nov 3, 2026
agent-note:v1 — task 8020 handed off (Lane A worker, 2026-11-03): execution lane assigned opencode; the claimant launches the bound session to drive task 8020 (slice 2 of this issue: script-backed tool views in mcpx) to its terminal state. Flag: task 8020 is at attempt 4 of 4 — if this lease expires without the session completing it, the task caps out and will need a cap raise or re-packet. This lane does not work it directly.
dezren39 commentedon Nov 3, 2026
agent-note:v1
state: handed_off
task: task 8020 (small_fix, repo-health-code-pilot, lane code-l)
worker: repo-worker-code
issue: #1933
Execution lane assigned: opencode. Handed off to the laptop claimant, which launches the bound session to drive task 8020 (script-backed tool views, slice 2 of #1933) to its terminal state.
dezren39 commentedon Nov 3, 2026
🤖 Agent note · handed off