Skip to content

mcpx: tool views and composed tool sets — rename/pin/hide, cross-server namespaces, script-backed tools, and generators that emit declarations #1933

Open

Description

@dezren39

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-28 adds ttlMs/cacheScope specifically 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" }
    }
  }
}
  • from renames; pin supplies fixed arguments the caller cannot set; hide removes pinned properties from the exposed inputSchema so the tool looks like what it is; description overrides. Selection (tools/excludeTools) stays as it is and a toolViews map implies the allowlist.

  • Composition across servers needs one more thing: a view whose from is a fully-qualified server.tool rather than a bare name, and a server entry with no aliasOf at all — a virtual namespace assembled from several targets. Registry.views is already map[string]*config.Resolved keyed 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 from d956689 to 36464cf #83's (Phase 3: sync, blob gate, and relays #181 collision 4). chore(deps): bump build/buck/preludes/buck2-prelude from d956689 to 36464cf #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 from d956689 to 36464cf #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 @param header already declares its holes with types — the same header recipes use — so inputSchema generates 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 from d956689 to 36464cf #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 from d956689 to 36464cf #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: false and 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.json keying, diagnostics, and internal/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 pin be 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.apis targets, a state directory, or stdout only? Stdout only is safest; a --write flag is the convenience.
  • Does a script-backed tool run through POST /v1/exec with the caller's ExecOptions, or with fixed options from its declaration? Fixed, probably, or a tool's behaviour depends on who called it.
  • Should tools/list mark 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

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    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.


    @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:

    #181 row Collision Owner What the owner decides
    4 namespacing and collision rules designed twice #83 #83's tool-source interface defines namespaces and collision rules; #114's views, cross-server namespaces and script-backed tools are built on those rules and do not define their own.

    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).


    @dezren39 · 2026-09-30T16:58:21Z

    Decided (SURFACES, 0002-autonomy-dial, merged in #228). Generators are propose by 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, code d2cb60fe8e08cd6fee149b930187b610299c1fa7):

    Route: no small_fix packet 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.

  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 29, 2026
  5. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done (triage)

    Triage verdict

    Dedupe. The four asks split across existing work more than the issue (written pre-relocation) could know:

    #1933 slice Where it lives
    Script-backed tools ("new commands that trigger its own scripts") Already covered by #2117 (split of #1875, triage task 2769): recipes as individual MCP tools with typed @param schemas. Same feature this issue calls "#83's first ship step" — #83 relocated here as #1875. Not re-enqueued.
    Generators emitting declarations for bare binaries Already covered by #2118 (split of #1875): one-shot generation into an editable declaration recording binary name + version — Approach C's model with runtime --help scraping rejected in the parent.
    Adding endpoints a vendor MCP omits, from its OpenAPI document Substantially the #2118 slice-3 verification (OpenAPI tools on the same namespace path) plus existing APISpec.Include. Credential extraction stays out of scope (this issue agrees).
    Declared tool views: rename / pin / hide / schema narrowing Unique to #1933. No other open issue covers it.
    Cross-server virtual namespaces (view from = server.tool, views with no aliasOf) Unique to #1933, but builds on #1875's namespace/collision rules — sequenced as slice 2.
    Generators emitting toolViews blocks (mcpx view generate) Recorded, not enqueued: the model half belongs to tracker #1891 (the AI layer). The deterministic runtime below is what such a generator would emit.

    Scope confirmed on current main (c58507a, 2026-10-29). aliasOf exists (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 across pkgs/mcpx/internal + docs: no toolViews, 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): toolViews on alias views — from (rename), pin (fixed args the caller cannot set), hide (pinned properties removed from the exposed inputSchema), description override; a toolViews map 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 exactly listTailnet + 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.

  6. 401 remaining items

  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    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).

  8. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    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.

  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  10. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked (shepherd prep done; needs a dedicated merge window)

  11. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    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.

  12. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    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.

  13. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1

  14. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — state: handed off — queue task 3230 launched in bound OpenCode session ses_e5e5f402149ffed9rlYheEb6Kx by opencode-claimant.

  15. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    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.

  16. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    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) has From, Pin, Hide, Description. From is mandatory in practice, so a view can only rename/arg-pin a tool that already exists on an aliased upstream server.
    • Materialisation: viewTools (pkgs/mcpx/internal/daemon/registry.go:~455) looks up byName[tv.From] and silently skips a missing target ("load-time validation names this"). There is no branch that manufactures a tool.
    • Alias→real mapping: ruleToolName (registry.go:~425) returns tv.From, and effectiveViewSchema (~438) keys argument rules off it. Both assume a real upstream tool name exists.
    • Visibility/preconditions: Resolved.VisibleTool (config.go:605) calls r.ExcludeTools.Match(tv.From) and r.PassesPreconditions(tv.From, nil) — both meaningless for a view with no upstream tool.
    • The executable machinery already exists and should be reused, not reinvented: adapter.Spec / adapter.ToolSpec / adapter.Param with ToolSpec.Schema() (pkgs/mcpx/internal/adapter/adapter.go:69,88,238) and Spec.Call (:283). That is exactly "a declared local command exposing typed tools".

    Proposed slice (for the implementer to confirm)

    1. Extend ToolView with a command-backed form: command, args, env, dir, timeout and a params/stdin/json shape borrowed from adapter.ToolSpec, so one view can be a script with typed arguments.
    2. Load-time validation: exactly one of from | command; a command view cannot declare pin of upstream properties; hide/pin keep their meaning for from views only. Name the error at the config boundary (same shape as existing ToolViews validation).
    3. Materialise command views in viewTools before the byName lookup, producing mcpclient.Tool with ToolSpec.Schema(), and route calls in the daemon's call path to adapter.Spec.Call, not the upstream client.
    4. Make ruleToolName and effectiveViewSchema handle a view with no From: rules key off the view name, and VisibleTool skips the upstream-only ExcludeTools/PassesPreconditions checks for command views.
    5. Tests: pkgs/mcpx/internal/daemon/toolviews_test.go already has the table-driven view cases; add (a) command view lists with typed schema, (b) call executes and returns output, (c) from+command together is a load error, (d) pin on a command view is a load error, (e) name collision with an upstream tool.

    Open questions to settle before coding

    • Does a command view belong in the views cache at all, or should it hang off the same registry the adapter tools use? The current viewTools signature takes all []mcpclient.Tool from one upstream — a script-backed view has no upstream to be cached beside.
    • Should mcpx ls list 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)

  17. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  18. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    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

  19. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    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.

  20. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    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.

  21. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: opencode-claimant
    • Session / ID: ses_e5e5d242960ffe2yVxmEWWxcJN · queue task 8020
    • Route: opencode-route/workhorse · build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestqueue/claimedQueue worker lifecycle statesource/creatorFiled by the new-issue-creator jobstatus/in-progressQueue worker lifecycle statetask/triageQueue packet kind: verify, reproduce, and route this itemwork/assignedQueue worker lifecycle state

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions