pastilhas 10378d08cc the plugin, start to finish: connection, pass-through, panels, skill
OpenSEO ships its own MCP server and its own web UI, so this plugin holds the
address, holds the credential, and is the door. There are no curated routes in
front of it and there should not be: proxy-manager's router already records
where that leads — a curated surface cannot keep up, and the plugin becomes a
worse version of the thing it wraps.

The door IS the security model, not a convenience. Upstream self-hosts with
AUTH_MODE=local_noauth, so every request reaching the instance is trusted by
design and their docs say to put it behind auth. Officer's gate is that auth.
Two things follow and neither is optional: nothing here may publish OpenSEO's
own port, and /_config is owner-only, because the address alone is enough to
bypass this plugin entirely. The iframe therefore points at /api/openseo/ — this
Officer's origin — and never at the instance, since an iframe src is a URL
anybody can read out of the page and open directly.

The probe asks /mcp for tools/list rather than fetching the home page. A web
root answers 200 for a great many things that are not this; a JSON-RPC reply
carrying tool names is the instance identifying itself.

Saving with an empty key field KEEPS the stored one — absent means keep, empty
string means clear. Without that distinction, changing the address from a form
that cannot display the credential would silently erase it, and it would surface
days later as an instance that had stopped answering.

One table, deliberately: every project, keyword and crawl lives in the instance,
so uninstalling this cannot destroy anybody's research. The skill says so too,
because the temptation to cache a project list is exactly what would break it.

The skill leads with cost. This is free software over DataForSEO, metered and
billed to the owner per lookup, so it tells the agent not to sweep and to say
what a thorough answer would spend before spending it.

Tags are `Development` and `Homelab`. `Marketing` and `Research` would both be
more accurate and neither exists in the union — extending it is a platform
change rather than a plugin's to make.
2026-08-29 18:42:43 +01:00
2026-08-29 15:03:47 +01:00
2026-08-29 15:03:47 +01:00

OpenSEO for Officer

Keyword research, rank tracking, competitor and backlink data, site audits — from every-app/open-seo, self-hosted, behind Officer's own permission gate.

Why this is a thin plugin

Most integrations need Officer to invent the agent-facing surface. This one arrives with its own: OpenSEO ships an MCP server at /mcp and its own Agent Skills, built to be driven by exactly this kind of client. So the plugin's job is credential plumbing, a permission boundary and a UI surface — not reimplementing a tool vocabulary that already exists upstream.

What it runs against

One container, verified from upstream's compose.yaml rather than its README:

ghcr.io/every-app/open-seo:latest
  port    3001, bound to 127.0.0.1
  data    a Docker volume at /app/.wrangler  (Cloudflare D1 — SQLite; Postgres is opt-in only)
  auth    AUTH_MODE=local_noauth

local_noauth is not a shortcut taken here, it is upstream's documented self-hosting mode — their docs say to "only expose it behind your own auth-protected reverse proxy, tunnel, or private network." That sentence describes an Officer plugin: mounted behind Officer's permission gate, never published on its own port. It is the ordinary case here rather than a risk to design around — but it is also why nothing in this plugin may expose OpenSEO's port directly, and why the pass-through is the only door.

Credentials, and the honest cost

DATAFORSEO_API_KEY Required. Base64 of login:password. Paid pay-as-you-go directly to DataForSEO
OPENROUTER_API_KEY Optional — OpenSEO's own AI features
GOOGLE_CLIENT_ID / _SECRET Optional — Search Console

This is free software over a metered API. Nothing here is a subscription to OpenSEO, and nothing here makes the DataForSEO calls free.

Decisions this scaffold does NOT make

Both are open in todo/integrations/openseo-a-plugin-candidate.md, and both are the owner's:

  1. Where the container runs. Today a plugin has no primitive for "bring a container" — osDependencies installs OS packages. todo/infra/opm-officer-s-own-process-manager is heading toward the Docker network, at which point a container-backed dependency needs no published host port at all. Until then this plugin points at an instance rather than owning one, which is what jellyfin, gitea and proxy-manager already do.
  2. Whether Officer's agents call /mcp directly, or Officer wraps it as native MCP tools. Direct is simpler and already works. Wrapping is more consistent with how other plugins expose theirs, and puts every call through one place that can log and refuse. This scaffold proxies, which keeps both open.
S
Description
OpenSEO for Officer — self-hosted keyword research, rank tracking and site audits, behind Officer's own permission gate.
Readme
50 KiB
Languages
TypeScript 100%