a plugin can hand the agent its own MCP server
openseo is the first: it fronts something that already ships an MCP server, and the choice was to reimplement that vocabulary as Officer tools or hand the real one over. Reimplementing means a second copy that goes stale, and it fails silently — a tool exists upstream that Officer cannot see. Handing it over costs one manifest field. What a wrapper would have bought — authentication, logging, refusal — is already true of the path, because the agent reaches it through Officer's own API with Officer's own gate in front. Wrapping would buy it twice. The manifest declares a PATH and never a URL, and that is the safety property rather than a convention: mcp-host.json carries OFFICER_AUTH_TOKEN, which signs as the owner, so a manifest able to name an arbitrary host would be a manifest able to post the owner's credential anywhere. A path can only reach this machine. Installed AND enabled, since a disabled plugin's routes are not mounted and offering the agent a tool list that 404s is worse than offering nothing. A plugin that cannot be read loses its tools for the session rather than stopping the agent from starting. `generateMcpConfig` becomes async because it now asks the database. Awaited, not fire-and-forget: setMcpConfigPath is what the manager reads when it spawns, so a config arriving later is an agent running without its plugin tools and no sign of why. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -523,6 +523,31 @@ export type PluginManifest = {
|
||||
*/
|
||||
hooks?: Partial<Record<string, string>>;
|
||||
|
||||
/**
|
||||
* An MCP server this plugin serves, offered to the agent as its own.
|
||||
*
|
||||
* ── Why a path and not a URL ──
|
||||
*
|
||||
* The path is under this plugin's own mount, so `/mcp` becomes `/api/<plugin>/mcp` on THIS Officer.
|
||||
* A URL would let a plugin point the agent at any host, and the agent's config carries a token that
|
||||
* signs as the owner — so the one field that must not be free-form is the destination.
|
||||
*
|
||||
* ── Why this exists rather than wrapping the tools ──
|
||||
*
|
||||
* A plugin that fronts something with its own MCP server — openseo is the first — can either
|
||||
* reimplement that vocabulary as Officer tools or hand the real one over. Reimplementing means a
|
||||
* second copy that goes stale, and it fails silently: a tool exists upstream that Officer cannot see.
|
||||
* Handing it over costs this field.
|
||||
*
|
||||
* What a wrapper would have bought — authentication, logging, refusal — is already true of the path,
|
||||
* because the agent reaches it through Officer's own API with Officer's own gate in front. Wrapping
|
||||
* would buy it a second time.
|
||||
*/
|
||||
mcp?: {
|
||||
/** Under the plugin's mount. `/mcp` on a plugin mounted at `/api/openseo` is `/api/openseo/mcp`. */
|
||||
path: string;
|
||||
};
|
||||
|
||||
osDependencies?: OsDependency[];
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user