Skip to content

feat(plugin): ship the Agent Gateway connector as a Claude Code plugin - #140

Merged
jheddings merged 15 commits into
mainfrom
feat/claude-marketplace-plugin
Aug 21, 2026
Merged

feat(plugin): ship the Agent Gateway connector as a Claude Code plugin#140
jheddings merged 15 commits into
mainfrom
feat/claude-marketplace-plugin

Conversation

@jheddings

@jheddings jheddings commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

A proof of concept for repositioning this repo toward agent integrations: it now additionally works as a Claude Code plugin marketplace, shipping one connector-only plugin that reaches the Workday Agent Gateway over HTTP MCP.

/plugin marketplace add Workday/everywhere
/plugin install everywhere@workday

Enabling prompts for a single value — the gateway's MCP endpoint — and sign-in happens through /mcp. Tools come from the gateway at runtime; the plugin ships no skills, commands, or agents.

What's added

Path Purpose
.claude-plugin/marketplace.json Marketplace workday, advertising one plugin
plugins/everywhere/.claude-plugin/plugin.json One required userConfig field, no default
plugins/everywhere/.mcp.json One HTTP MCP server: a transport and a templated URL
plugins/everywhere/README.md Install, configure, connect, troubleshoot
tests/claude-plugin/manifest.test.ts 20 manifest-shape and safety assertions
.justfile bundle-plugin recipe for Cowork upload

Two properties the tests enforce mechanically

Nothing about a gateway is hard-coded. The gateway_url field declares no default, and an allow-list assertion requires every value in the connector to be a ${user_config.*} template, with no literals permitted at all. A hard-coded hostname, tenant, or token fails the suite.

No credential material is committed. The connector declares no oauth block. This is not just preference: ${user_config.*} and environment-variable expansion apply to env, url, and headers, but not inside oauth, so a client ID there could only ever be a committed constant. Sign-in instead uses OAuth discovery plus dynamic client registration.

Additive by construction

src/, cli/, bin/, and package.json are untouched. package.json uses an explicit files allowlist, and npm pack --dry-run confirms no plugin files enter the published tarball. Downstream @workday/everywhere consumers are unaffected.

Verification

  • just check and just test pass — 557 tests, 20 of them new
  • claude plugin validate passes for both the plugin and the marketplace manifest
  • npm pack --dry-run shows no plugin files in the tarball

Open question this POC exists to answer

Whether the gateway supports dynamic client registration. Prior internal work disagrees on this, and it decides whether sign-in works out of the box. If DCR is unsupported, the plugin still works via the manual claude mcp add --client-id … --callback-port … path documented in the plugin README — that would be a docs change, not a redesign.

For reviewers

  • The custom headers were removed on a recollection, not a verified contract. Per review feedback, WD-Tenant, WD-Agent-Tenant-Alias, and wd-agent-interaction-channel are no longer required, so they and their two config fields are gone and tenant routing now rests entirely on the tenant-scoped URL path. That matches what one of the two prior prototypes has always done. Still worth confirming with the AF team before merge — restoring them means re-adding the two fields, the headers block, and a permitted-literal exception in the allow-list test.
  • The root README.md is deliberately untouched, so nothing yet tells a reader this marketplace exists. Intentional for a POC; worth a decision before any merge.

🤖 Generated with Claude Code

jheddings and others added 14 commits August 20, 2026 14:25
Spec for a connector-only Claude Code plugin exposing the Workday Agent
Gateway over HTTP MCP, installed from a marketplace manifest at the repo
root. Additive: the npm package and SDK surface are untouched.

Records the constraint that drove the auth design — ${user_config.*} and
env-var expansion do not apply inside the MCP oauth object, so a templated
client ID is not expressible and sign-in relies on discovery plus dynamic
client registration instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Six TDD tasks: plugin manifest, connector, marketplace manifest, README,
Cowork packaging recipe, and full verification. Ordered so the plugin
directory exists before the marketplace points at it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ?? {} fallback let 'runs no local command' and 'commits no OAuth
client material' pass against an empty object when the server was
renamed or missing. The https:// substring check passed on http:// and
on bare hostnames.

Replace both with a guard that throws when no workday server is
declared, and an allow-list assertion requiring every connector value
to be a user_config template apart from the fixed interaction channel.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous value, https://anthropic.com/claude-code/marketplace.schema.json,
returns 404. Replace it with the SchemaStore definition, which resolves and
matches this file's shape (required name/owner/plugins; entries keyed on
name/source).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dynamic client registration support is unverified, so the Connect
section now names the failure case and points at the fallback instead
of stating that no client ID is ever needed. Also puts the redirect-URI
prerequisite ahead of the command that depends on it, and replaces the
unactionable 'reconfigure the plugin options' fix with the settings
file the values are actually read from.
The -x '.DS_Store' pattern only matched at the archive root, so a
.DS_Store inside .claude-plugin/ shipped in the uploaded bundle. And
jq returned the string "null" for a missing version field, silently
producing everywhere-plugin-null.zip instead of failing.

Switch to the shebang-block form the other multi-line recipes use, so
the version guard reads without continuations.
The spec is committed to a public repository, so it should not name
internal repositories or codenames. Describe the two prior prototypes
by what they do instead. No design decision changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The spec's connector list predated the safety-test hardening: it still
described a literal https:// substring check and omitted the allow-list
assertion and the throwing server guard that replaced it. The plan's
Task 3 block still showed the vacuous entry?.source ?? '' form that the
implementation never used.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@mpfilbin mpfilbin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of small observations - nothing blocking.

Comment thread plugins/everywhere/.claude-plugin/plugin.json Outdated
Comment thread plugins/everywhere/.mcp.json Outdated
The gateway team removed the requirement for WD-Tenant,
WD-Agent-Tenant-Alias, and wd-agent-interaction-channel, so the
connector is now just a transport and a URL. Tenant routing rests on
the tenant-scoped URL path.

Removes the two userConfig fields that existed only to populate those
headers, taking the configuration surface from three prompts to one.
The allow-list safety test gets stricter as a result: with no fixed
channel value to permit, every connector value must now be a
user_config template with no literals allowed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jheddings
jheddings merged commit fc36096 into main Aug 21, 2026
2 checks passed
@jheddings
jheddings deleted the feat/claude-marketplace-plugin branch August 21, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants