claude-plugin-template
A multi-plugin workspace for building Claude Code plugins with skills, MCP tools, and an OAuth-protected HTTP server — ready to deploy to any cloud.
What's included
packages/mcp-server— shared MCP infrastructure: Express server, Azure Entra/OIDC auth, session management, widget supportplugins/standard— starter plugin with awhoamitool andexampleskill- Build and validation scripts — typecheck, lint, skill validator, widget bundler
Getting started
git clone https://github.com/varianter/claude-plugin-template
cd claude-plugin-template
cp .env.example .env # fill in your auth credentials and config
pnpm install
Then update plugin.config.json with runtime configurations. See below for details.
Run a plugin's MCP server locally:
pnpm dev:standard # hot-reload server + widget watcher
pnpm dev:server:standard # server only — faster when not touching widgets
Then update plugins/standard/.claude-plugin/plugin.json with your MCP server URL once deployed.
Configuration
Runtime defaults live in plugin.config.json. Environment variables override these values at runtime. Commit only safe, shared defaults; put secrets and environment-specific values in .env, plugin.config.local.json (gitignored), or your deployment environment.
Safe to commit as shared defaults:
mcpPath— HTTP endpoint path for MCP requests; clients must use this route.auth.enabled— turns OAuth/OIDC protection on or off; needed to require authenticated access.auth.provider— identity provider type (entra,auth0,okta, etc.); needed for provider-specific OAuth metadata.auth.scopes— scopes requested during login; needed to control what access tokens can contain.auth.scopeAliases— extra scope names mapped for Entra compatibility; needed for Claude/MCP client interoperability.auth.compatibilityProxy— enables compatibility OAuth endpoints; needed for clients that cannot use the provider directly.auth.clientRegistration— dynamic registration mode (none,provider,static); needed to tell clients how to obtain a client ID.limits.maxSessions— maximum concurrent MCP sessions; needed to cap memory and connection usage.limits.rateLimitPerMinute— per-minute request limit; needed to protect the server from bursts or abuse.
Can be committed if shared across deployments; otherwise set via environment:
auth.tenantId/AUTH_TENANT_ID— Entra tenant ID; used to derive the issuer URL for Microsoft Entra.auth.issuerUrl/AUTH_ISSUER_URL— OAuth/OIDC issuer URL; needed to discover metadata and validate tokens.auth.clientId/AUTH_CLIENT_ID— OAuth client/application ID; needed for login and token audience checks.auth.audience/AUTH_AUDIENCE— requested token audience; needed when the provider expects an explicit API audience.auth.acceptedAudiences/AUTH_ACCEPTED_AUDIENCES— extra JWT audiences to trust; needed when clients send provider-specific audience values.auth.acceptedIssuers/AUTH_ACCEPTED_ISSUERS— extra JWT issuers to trust; needed for provider aliases or multi-issuer setups.auth.allowedRedirectOrigins/AUTH_ALLOWED_REDIRECT_ORIGINS— allowed OAuth redirect origins; needed to prevent unsafe redirect targets.
Environment-only secrets:
AUTH_CLIENT_SECRET— OAuth client secret; required only for confidential-client flows and intentionally not supported inplugin.config.json.
$schema may be included only to give editors validation and autocomplete. See plugin.config.schema.json for valid types and enum values.
Project structure
packages/
mcp-server/ ← @variant/mcp-server — shared server infrastructure
plugins/
standard/ ← starter plugin (copy this to add a new plugin)
.claude-plugin/
plugin.json ← plugin manifest (skills paths, MCP server URL)
skills/ ← skills; each skill may optionally contain an mcp/ directory for colocated tools
skills/*/mcp ← MCP tools colocated with a skill (optional)
tools/ ← standalone MCP tools (not tied to a skill)
mcp/ ← deployable MCP HTTP server for this plugin
.claude-plugin/
marketplace.json ← repo-level manifest listing all plugins
scripts/ ← skill validator and packaging tools
plugin.config.json ← committed runtime defaults for MCP servers
Adding a skill
Create plugins/standard/skills/<name>/SKILL.md. If the skill needs MCP tools, add them under plugins/standard/skills/<name>/mcp/:
---
name: my-skill
description: One-line description shown in the skill picker
---
Skill instructions here.
Validate it:
cd scripts && pnpm exec tsx validate.ts ../plugins/standard/skills/my-skill
Adding an MCP tool
Create plugins/standard/tools/<name>/<toolName>.ts with an explicit registrar:
import type { McpServer } from '@variant/mcp-server';
import { z } from 'zod';
export function registerMyTool(server: McpServer): void {
server.registerTool(
'my-tool',
{ title: 'My Tool', description: 'Does something useful', inputSchema: { param: z.string() } },
async ({ param }) => ({ content: [{ type: 'text', text: param }] }),
);
}
Then add it to plugins/standard/mcp/registerTools.ts:
import { definePluginTools } from '@variant/mcp-server';
import { registerMyTool } from '../tools/my-tool/myTool.js';
export const registerTools = definePluginTools([registerMyTool]);
For skill-colocated tools (tools under a skill's mcp/ directory) see AGENTS.md.
Adding a new plugin
1. Copy plugins/standard/ to plugins/<name>/ 2. Update plugins/<name>/.claude-plugin/plugin.json and plugins/<name>/package.json 3. Add the new plugin to .claude-plugin/marketplace.json 4. Add it to the options list and matrix in .github/workflows/deploy.yml
Development commands
From the repo root:
pnpm dev:standard # standard plugin — server + widget watcher (hot-reload)
pnpm dev:server:standard # standard plugin — server only (faster, skips widgets)
pnpm build # build all packages in dependency order
pnpm typecheck # type-check all packages
pnpm check # biome lint + format check
pnpm fix # biome auto-fix
Additional commands available from plugins/standard/:
pnpm jam # MCPJam inspector UI
pnpm inspect # official MCP Inspector
Deployment
Trigger the Deploy GitHub Actions workflow from the repository UI. Select a plugin (or "all") and environment. Each plugin has its own Docker image (<plugin>-mcp) built from plugins/<plugin>/mcp/Dockerfile.
Update the registry and deployment target in .github/workflows/deploy.yml to match your infrastructure.
See CLAUDE.md for the full structure reference and AGENTS.md for the tool authoring guide.




