Skip to content

mcpx: Dropbox/Drive/Outlook/Tailscale, and a feedback loop built from evidence mcpx already collects #1936

Open

Description

@dezren39

Relocated from dezren39/darwin-nix#115 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

Two things: add four specific servers (Dropbox, Google Drive, Outlook, Tailscale), and give mcpx a channel for "you should add this" / "this one is slow, host it locally" so that the first thing is not a manual pipeline forever.

The second is the more interesting one, and the finding is that mcpx should not grow a curated vendor list. It already has registry search, live server add, and CLI→MCP adapters; what it is missing is the memory and the ranking — a record of what a user wanted and could not find, and enough metadata to answer "is there a better instance of this than the one I am using". A curated list of four servers is a snapshot that rots; a good search-add-record loop keeps working.

Original notes

  • mcp-owned opencode api support
    • add the dropboxMcp, googleDriveMcp, outlookMcp, tailscaleMcp
    • 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
    • accept user feedback, requests, routinely implement features/interfaces that are good idea. "you should add this mcp it's free." "this mcp is very good you should consider hosting it locally because the public one is slow and limited"

Current state (what mcpx does today, with file refs)

capability where
search the public MCP registry GET /v1/registry/search, internal/registry/registry.go:153 (pins version=latest at :158; matches server names only, as a substring), mcpx registry search|show|add (internal/cli/registry.go:15) — there is no mcpx connect
add a registry server to config mcpx registry add <name> prints the entry and the variables it needs; --write adds it (internal/cli/registry.go:92-124). No verify-it-starts step, no rollback.
add a server live, project or user scope POST /v1/servers (internal/api/ops_settings.go:82) — command/args/env or url/headers/transport, plus mcpx extras
remove a server live DELETE /v1/servers/{name}
expose one server as several filtered namespaces aliasOf + mcpx.tools (docs/story.md §"Profiles and aliases")
wrap a CLI program as a server internal/adapter, paths.adapters
wrap an OpenAPI service as a server internal/openapi, paths.apis, mcpx api --spec
credentials mcpauth.Auth on a server entry; ${VAR} expansion in APISpec.Headers; OAuth for remote servers is declared and not performed (docs/protocol.md §6)
per-server latency and error statistics GET /v1/stats — calls, servers, instances, errors, sessions, volume, slowest
a feedback channel none
a record of a search that found nothing none

The statistics row matters: mcpx already measures exactly the thing the note's second quote is about ("the public one is slow and limited"). It measures it and does nothing with it.

What exists for the four requested servers

Queried the official registry, https://registry.modelcontextprotocol.io/v0/servers?search=<name>, on 2026-09-30. Results are noisy — the same package is returned several times under different versions — and deduplicated here. (That is the raw API queried without version=latest. mcpx always sends the pin, internal/registry/registry.go:158, and gets distinct names — see #179.)

requested found notes
Dropbox io.github.pipeworx-io/dropbox ("Dropbox MCP Pack — wraps the Dropbox API v2"), ai.smithery/cindyloo-dropbox-mcp-server (search/browse/read), io.usefulapi/dropbox-sign (a different product — Dropbox Sign) no first-party Dropbox entry; all third-party
Google Drive search=google drive → 0 results; search=gdrive → 0 results. Only com.mcparmory/google-drive surfaced, under search=drive no first-party Google entry in the registry. The best-known Drive server is the gdrive reference server from modelcontextprotocol/servers, which was moved to the archived set. Effectively: nothing well-maintained and official.
Outlook io.github.chrischall/office-outlook-mcp (mail, calendar, contacts, tasks), io.github.0xka13b/microsoft-outlook-mcp (read/search/send), com.mintmcp/outlook-email, com.mintmcp/outlook-calendar no first-party Microsoft entry under this search. Microsoft ships MCP for other products; Outlook coverage here is third-party.
Tailscale io.github.YawLabs/tailscale-mcp ("manage your tailnet from AI assistants"), ai.dinglebear/rtailscale (devices, routes, DNS, keys, users, ACLs — MCP and CLI), ai.dinglebear/tailscale-rmcp (Rust MCP server and CLI) no first-party Tailscale entry.

Two conclusions:

  1. None of the four has a first-party server. Every option is community-maintained, of unknown quality, and requires handing it a credential to a fairly consequential account. That is a reason to prefer the thinnest possible wrapper, not the richest one.
  2. Three of the four have an excellent official CLI or HTTP API, which mcpx can already consume without any MCP server. tailscale the CLI covers status --json (hostnames, tailnet, devices) and the Tailscale API is documented and simple; Microsoft Graph and the Dropbox API v2 both publish OpenAPI-ish documents. So internal/adapter and internal/openapi are a better route than adopting a third-party server: the declaration is reviewable, the credential handling is ${VAR} expansion, and there is no extra process from an unknown author in the trust path.

For the specific tailscale request — an alias exposing only listTailnet and listHostnames — the cheapest correct answer is an adapter spec over the tailscale CLI, about fifteen lines:

{ "name": "tailscale", "command": "tailscale",
  "tools": [
    { "name": "listTailnet",   "args": ["status", "--json"], "json": true },
    { "name": "listHostnames", "args": ["status", "--json"], "json": true }
  ] }

It requires no auth because the local tailscale CLI is already authenticated — which is the literal reading of "it should accept the creds i already used to connect to it". The renaming and narrowing that an alias over a real MCP server would need is the toolViews work in #114; the adapter route needs none of it, because an adapter declares its own tool names. Worth doing as the first proof that adapters are the right default for this class of request.

Approaches

Approach A — least recommended: ship a curated list of vendor servers in mcpx's defaults

Bundle known-good entries for Dropbox, Drive, Outlook, Tailscale and others in internal/defaults, so mcpx registry add dropbox just works.

Why not:

  • It is a snapshot of a directory that already exists and is maintained by someone else. The registry is the curation layer; duplicating a slice of it into a Go binary means every entry rots at its own rate and a stale one is worse than no entry, because it carries mcpx's implicit endorsement.
  • It makes mcpx an opinion about third-party code quality across products it does not use, for a trust decision (handing over a Dropbox or Microsoft 365 credential) that is genuinely consequential and genuinely the user's.
  • It answers the wrong question. A user asking for "the Dropbox MCP" wants Dropbox capability, not a specific package. The registry answers "which packages exist"; nothing today answers "which of these should I use", and a hard-coded list does not answer it either — it just hides the question.
  • It also scales badly: there are thousands of servers and four is not a stopping point anyone will respect.

Approach B — middle: make discovery and adoption good, and document the four as recipes

Improve what exists rather than adding a list:

  1. Registry metadata in search output. The registry carries more than name and description; surface what it has — package type, transport, remote-or-local, version recency, whether it is official. "Is this maintained" is the first question and today the answer requires leaving mcpx. Part of it is already fetched and thrown away: each result's _meta is decoded into listResponse (internal/registry/registry.go:137-146) and dropped at :168-169. It carries io.modelcontextprotocol.registry/official with status, publishedAt, updatedAt and isLatest (checked live 2026-09-30).
  2. Deduplicate registry results. The raw responses above return the same server up to nine times across versions. internal/registry should collapse by name and show the newest version, which is a small, clearly-correct fix (visible directly in the query output quoted above). Struck (issues pass, 2026-09-30, at 05c78b2): mcpx never sees those duplicates. Search pins version=latest on every query (internal/registry/registry.go:158), every caller goes through it, and five live searches returned all-distinct names (Phase 3: /id-sync/1 is used by both range and LogSync handshakes #179). The duplicates belong to the un-pinned raw query above, which mcpx does not issue. What Phase 3: /id-sync/1 is used by both range and LogSync handshakes #179 found instead, and owns: registry.pageSize is only consulted when limit <= 0 (:155), and nextCursor is parsed (:143) and dropped, so a search silently stops at one page.
  3. mcpx registry add <name> end to end (this issue first called it mcpx connect, which does not exist; the command is mcpx registry): search, pick, show what it will run and what credentials it wants — registry show/add already do this much — add it at project or user scope, verify it starts and lists tools, and roll back if it does not. POST /v1/servers plus /v1/health already provide the rest.
  4. Prefer an adapter or an OpenAPI declaration when one is available. When a requested capability has a well-known CLI or published API document, say so: "tailscale is installed; an adapter declaration needs no credential and no third-party process. Generate one?" That is a better default than adopting an unknown server, and it connects directly to the spec-generation work in Update checkmarx/ast-github-action digest to 6c56658 - autoclosed #114.
  5. Ship the four as documented example declarations, in docs/, not in defaults — copy-pasteable, reviewable, and obviously not endorsed-and-maintained by mcpx.

This is all deterministic and most of it is small.

Approach C — recommended: B, plus a recorded feedback loop that mcpx can actually act on

Do B. Then close the loop the second bullet is asking for — and note that the useful version of it is mostly evidence mcpx already has, not free text.

1. Record the misses. Every mcpx search and registry search that returned nothing or was followed by no call is a data point. Store them (the event store, #6, is the natural home) and expose mcpx feedback / GET /v1/feedback as the local list: "you searched for calendar 6 times in 3 sessions and never called a tool." That is a concrete, unarguable statement of a missing capability, derived at zero cost from telemetry that already flows through /v1/log.

2. Turn statistics into a recommendation. "This mcp is very good you should consider hosting it locally because the public one is slow and limited" is a measurement, and /v1/stats already has slowest, errors and volume per server. A mcpx doctor check — and doctor already exists (internal/cli/doctor.go) as the place mcpx tells you what is wrong — can say: "notion (remote): p95 4.2s over 340 calls, 6% errors. A local package exists in the registry. Switch?" Remote-versus-local is visible in the config (url versus command), and the registry says whether a local package is published. This is the single best item in this issue: it is deterministic, it uses only data mcpx already collects, and it produces exactly the advice the note quotes.

3. Accept explicit feedback as a first-class record. mcpx feedback "add a calendar mcp" / POST /v1/feedback, appended to a local file with the context mcpx can attach automatically (which servers are configured, which searches failed, what the daemon version is). Local by default and never transmitted anywhere. Its purposes, in order: it gives the user a place to put the thought, it gives mcpx prompt something to act on, and it gives a maintainer a file to paste into an issue if the user chooses to.

4. Let the prompt layer read it. With #113's intent --scope ops, "add the thing I keep failing to find" becomes: read the miss log, search the registry, propose a server or an adapter declaration, show the plan, add on confirmation. Every step is an existing declared operation; the model only chooses among them. That is "routinely implement features/interfaces that are good idea" in the only form that is safe — mcpx proposing, the user approving.

5. Explicitly out of scope: mcpx modifying itself in response to feedback. The note's "routinely implement features" could be read as self-modification. It should not be. The loop ends at a proposal a human accepts; anything past that is the arbitrary-provisioning question deferred in #113.

Recommended because it converts a vague "accept feedback" into three concrete, mostly-deterministic features built on data mcpx already has; because the slow-remote-server recommendation is genuinely valuable and genuinely cheap; and because it avoids taking on the maintenance and the implied endorsement of a vendor list.

Open questions

  • Where do feedback and miss records live — the event store (Bump build/buck/preludes/buck2-prelude from 3a02ea3 to 4371899 #6), a plain JSONL file in the state dir, or the log store? The log store has query, filtering and retention already; a separate file is simpler to hand to a maintainer.
  • Should a miss record capture the query text? It is the useful part and it is also the most sensitive thing in the file. Local-only mitigates it; an explicit opt-out setting is probably still required.
  • Does mcpx registry add verifying a server by starting it constitute running untrusted code before the user consented? Almost certainly — the consent has to come before the first launch, not after.
  • Is there a registry field for "official/verified"? The io.github.* versus com.*/ai.* namespacing implies provenance but does not assert maintenance. Partly answered: per entry, /v0/servers returns _meta["io.modelcontextprotocol.registry/official"] with a lifecycle status (e.g. active) and dates — registry lifecycle, not a quality or verification signal.
  • Should mcpx ever propose self-hosting a remote server automatically (pull the package, run it locally, rewrite the config, keep the credential)? Attractive and a large step; the rollback story if the local one is worse must exist first.
  • For Google Drive specifically: with no maintained server, is a Google Drive OpenAPI declaration (Drive API v3 publishes a discovery document) the better answer? Probably, and it generalises to every Google API at once.

Ease · Impact · Related

Ease M (S for richer metadata + the four example declarations — registry dedup struck, see #179; M for mcpx registry add end-to-end and the doctor recommendation; M for the feedback/miss store) · Impact medium-high — the doctor recommendation and the miss log are the parts that keep paying; the four servers are a day's config each once adapters are the route.

Depends on / related: #179 (registry search gaps: unreachable registry.pageSize, dropped nextCursor; disproved the dedup premise), #6 (event store, for miss records), #76 (ops/CLI parity for any new operation), #5 (config chain, for add scope). Siblings: #114 (toolViews.from is what an alias over a real tailscale MCP server would need; adapter/OpenAPI generation is the recommended route for all four), #109 (a miss is a search that found nothing — the two share the record), #113 (intent --scope ops is what acts on the feedback), #110.

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#115 (verbatim, oldest first):


    @dezren39 · 2026-09-30T07:21:55Z

    Integration pass. Placed in the DAG rooted at #181.


    @dezren39 · 2026-09-30T07:29:28Z

    Integration pass — the registry-deduplication premise in Approach B is disproved. Strike item 2.

    Verified at 8001f23 and written up in #179. internal/registry/registry.go:158 sets
    version=latest unconditionally on every search, and every caller reaches the registry through
    that one query builder (internal/cli/registry.go:38,221, internal/daemon/ops.go:287). Five
    live searches returned 3/3, 7/7, 19/19, 50/50 and 11/11 distinct names — zero duplicates.

    The large duplicate counts are real but belong to the un-pinned query, which mcpx never issues:
    without version=latest, filesystem returns 90 rows for 11 distinct names, a maximum of 72
    repeats of one package. That is almost certainly where the "up to nine times" figure came from.

    Item 1 of Approach B — surfacing the registry metadata that is already fetched in search
    output — is untouched by this and is still worth doing.
    Only the dedup half is obsolete.

    Two genuine defects were found in the same 400 lines and are filed in #179 instead:
    registry.pageSize is consulted only inside if limit <= 0, so no ordinary caller can reach it;
    and nextCursor is parsed off the response and dropped, so search silently truncates at one page.

    Tracked in the DAG at #181 · this issue sits under #176.


    @dezren39 · 2026-09-30T11:57:50Z

    Issues pass (2026-09-30, at 05c78b2).


    @dezren39 · 2026-10-28T22:35:58Z

    Triage verdict (task 2162, repo-health-nix-pilot): PARTIALLY LANDED + CONFIRMED remainder, RELOCATED — a feedback store with ranking influence exists in the new home, but it is not the channel this issue asked for, and none of the four servers has been added. mcpx-side routes in developing-today/code; no fix packet in this repo.

    Verified against current main on both sides (nix 224c7b738e88c7a8e5d406987a7d88257e229db2, code d2cb60fe8e08cd6fee149b930187b610299c1fa7):

    • Update github.com/charmbracelet/promwish digest to 6c16e8f - autoclosed #115 is OPEN with labels enhancement, design — no hard-stop labels. Parent tracker Nix Playwright E2E suite fails after vendoring dependencies #176 is OPEN.
    • The mcpx source no longer lives in dezren39/nix: no pkgs/mcpx at 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.
    • Landed since this issue was written, in developing-today/code: a real feedback substrate. logstore.FeedbackStore (pkgs/mcpx/internal/logstore/feedback.go) persists interaction records with execution/retrieval scores in SQLite; POST /v1/feedback (internal/api/ops.go:651, "Submit quality feedback for a trace… for adaptive routing") attaches scores to a trace; interactions are recorded from the proxy and daemon paths (internal/daemon/routes_proxy.go:200,256, server.go:920); and the scores actually move ranking — SearchSemantic applies ToolFeedbackAdjustment multipliers (internal/daemon/registry.go:559-560). "mcpx measures and does nothing with it" is no longer true of call outcomes.
    • Still missing, i.e. the channel this issue actually asked for: (a) a record of a search that found nothing — nothing in logstore, the feedback routes, or the search path records a miss (the store records interactions and caller-submitted scores, not empty searches); (b) a "you should add this / host this locally, the public one is slow" request channel — there is no suggestion/request operation in the ops table, and the landed feedback targets a trace that already happened, not a capability that does not exist yet; (c) the "is there a better instance of this" answer built from the stats mcpx collects.
    • The four servers: none added. No Dropbox/Drive/Outlook/Tailscale entry in this repo's mcpx.config.nix, and no shipped adapter spec in code — the issue's own cheapest proof, the ~15-line tailscale CLI adapter exposing listTailnet/listHostnames, does not exist in either repo (listTailnet appears nowhere). Per the issue's own conclusions, adding them is an adapter/openapi declaration plus handing a consequential account credential to it — a decision for the config owner, not a default to bundle (Approach A is the one it recommends against).

    Route: no small_fix packet in dezren39/nix. The mcpx-side remainder (search-miss record, request channel, better-instance ranking) belongs with the source in developing-today/code, referencing #115, via the #309 relocation pass; per the cross-repo rule, do not re-file it there. The four-server add stays a nix-side config decision for Drew when he wants one of them, with the tailscale adapter as the recommended first proof. #115 stays open on the nix side until then.

  3. 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
  4. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  5. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    Triage verdict — not a duplicate; scope confirmed on current main; split, best item enqueued first

    Dedupe: no existing code issue covers this. #1982 (front codex-connectors for OAuth apps) and #1950 (OAuth authorization, 61 conformance rows) are adjacent to the four-servers half but are different work — neither records feedback/misses nor recommends from stats. Note a naming collision the follow-ups must respect: mcpx feedback already exists (internal/cli/feedback.go) but it is trace scoring (retrieval/execution scores for a trace-id), not this issue's "you should add this" suggestion channel — the channel in item 3 below still does not exist.

    Scope check against current pkgs/mcpx main (2026-10-29, via GitHub API):

    • Registry search/add, live server add/remove, aliasOf filtered namespaces, CLI adapters (internal/adapter) and OpenAPI wrapping (internal/openapi) all present as the issue describes — the adapter/OpenAPI route for the four servers is available today.
    • GET /v1/stats per-server statistics present; internal/cli/doctor.go checks cover runtime/git/settings/config/server commands — no stats-driven recommendation check exists.
    • No shipped adapter/OpenAPI declarations for tailscale/Dropbox/Drive/Outlook (tailscale appears only in docs/ideas.md); the issue's ~15-line tailscale adapter spec remains unbuilt.
    • No miss record for empty searches and no suggestion feedback channel (see the mcpx feedback collision above).

    Split (issue stays open as the tracker):

    1. Doctor slow-remote recommendation — the issue's own "single best item": deterministic, uses only existing stats. Enqueued now as queue task 3233 (small_fix).
    2. Tailscale adapter declaration (class S, spec already in the issue body) — next split piece.
    3. Miss recording + suggestion feedback channel (class M; storage question — event store vs JSONL vs log store — is an open question on the issue; naming must avoid the existing trace-scoring feedback command).
    4. Dropbox / Drive / Outlook declarations via adapter/OpenAPI once piece 2 proves the pattern; Drive likely wants the Google discovery-document route per the issue's open question.

    Verification for the follow-up: pkgs/mcpx: go test ./... via CI on its PR.

  6. 25 remaining items

  7. added
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  8. 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

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

    @dezren39
    MemberAuthor

    agent-note:v1
    state: picked up
    queue: repo-health-code-pilot
    task: 8142 (small_fix, worker repo-worker-code, lane code-n, direct execution lane)
    by: repo-queue-worker-shift-n
    at: 2026-11-04T02:25Z

    Scope (task 8142, #1936 item 1 only): ship the tailscale adapter declaration from the issue body — paths.adapters spec over the local tailscale CLI exposing only listTailnet and listHostnames (tailscale status --json, json: true), no auth (the local CLI session is the credential). Fresh revalidation: issue #1936 OPEN, no hard-stop labels, no open PR for this item (PR #2597 was the separate doctor item, merged). Dropbox/Drive/Outlook declarations and the feedback loop are NOT in this task. Branch: queue/8142-1936-tailscale-adapter.

  11. added a commit that references this issue on Nov 4, 2026
  12. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: done
    queue: repo-health-code-pilot
    task: 8142 (small_fix, worker repo-worker-code, lane code-n, direct execution lane)
    by: repo-queue-worker-shift-n
    at: 2026-11-04T02:12Z

    Done: PR #5245 merged (merge commit 6a1a351) — ships the tailscale adapter declaration for #1936 item 1: pkgs/mcpx/examples/tailscale.json (spec over the local tailscale CLI, exactly listTailnet + listHostnames, both status --json with json: true, no credential — the CLI's existing session is the auth), pinned by TestShippedTailscaleAdapterDeclaration in pkgs/mcpx/internal/cli/adapter_shipped_test.go, documented in docs/configuration.md.

    Verified before merge: targeted tests pass on the laptop (go test ./internal/cli/ -run TestShippedTailscaleAdapterDeclaration, go test ./internal/adapter/), mcpx adapter check against the shipped file reports "1 adapters, all runnable", Codex review completed on the merged head 82de3aa with no findings. The two guard checks were still queued at merge (fleet runner congestion, #2605); the change's substance was verified directly, per the standing merge directive.

    Issue #1936 stays open: Dropbox/Drive/Outlook declarations (gated on PR #4637 per the task 7801 triage) and the feedback/miss loop remain.

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 requestsource/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions