maintenance

Investigate, adopt, and verify dependency updates — with special handling for `@cyanheads/mcp-ts-core`. Captures what changed, understands why, cross-references against the codebase, adopts framework improvements, syncs project skills, and runs final checks. Supports two entry modes: run the full flow end-to-end, or review updates you already applied.

8 stars

Best use case

maintenance is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Investigate, adopt, and verify dependency updates — with special handling for `@cyanheads/mcp-ts-core`. Captures what changed, understands why, cross-references against the codebase, adopts framework improvements, syncs project skills, and runs final checks. Supports two entry modes: run the full flow end-to-end, or review updates you already applied.

Teams using maintenance should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/maintenance/SKILL.md --create-dirs "https://raw.githubusercontent.com/cyanheads/pubchem-mcp-server/main/skills/maintenance/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/maintenance/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How maintenance Compares

Feature / AgentmaintenanceStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Investigate, adopt, and verify dependency updates — with special handling for `@cyanheads/mcp-ts-core`. Captures what changed, understands why, cross-references against the codebase, adopts framework improvements, syncs project skills, and runs final checks. Supports two entry modes: run the full flow end-to-end, or review updates you already applied.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

## When to Use

- After running `bun update --latest` yourself and wanting to review the impact (**Mode B** — typical)
- To run the whole flow end-to-end — outdated check → update → investigate → adopt → verify (**Mode A**)
- Periodically, to check for skill drift from the package

## Entry Modes

| Mode | Starting Point | First Step |
|:-----|:---------------|:-----------|
| **A — Full flow** | Lockfile is current; want to update | Step 1 |
| **B — Post-update review** | User already ran `bun update --latest` + `bun run rebuild` + `bun run test` | Skip to Step 3 with the update output or a `bun.lock` diff |

Both modes converge at Step 3 and end at Step 8.

## Steps

### 1. Survey what's outdated (Mode A only)

```bash
bun run devcheck --only outdated
```

Wraps `bun outdated` with the project's `devcheck.config.json` allowlist applied, so intentionally-pinned packages don't surface as actionable. Plain `bun outdated` works too if you want the unfiltered view.

Note: `bun update --latest` crosses semver majors; `bun update` alone respects ranges. Use `--latest` unless a package is intentionally pinned.

### 2. Apply the update (Mode A only)

```bash
bun update --latest
```

Capture the `↑ package old → new` lines from stdout — these feed Step 3. Alternatively, diff `bun.lock` to surface version deltas after the fact.

### 3. Investigate changelogs

Invoke the **`changelog`** skill with the captured list of updated packages. It resolves each repo, fetches release notes (or CHANGELOG entries) between old and new versions, and cross-references changes against actual imports in `src/`. Output per package: what changed, impact on this project, action items.

Do not redo this investigation inline — the `changelog` skill handles tag-format detection, monorepo patterns, and fallbacks. If the skill cannot resolve a package (private repo, no tags, no CHANGELOG), note it in Step 8 under "Open decisions" and proceed.

### 4. Framework review (`@cyanheads/mcp-ts-core`)

**Skill-version paradox.** If `node_modules/@cyanheads/mcp-ts-core/skills/maintenance/SKILL.md`'s `version` exceeds the one running, run Step 5 Phase A first and re-invoke `maintenance` — otherwise feature-adoption rows added in the new version silently don't surface. After Phase A, confirm the running skill version matches the package before continuing. If the session still has the old skill loaded, exit and restart.

If `@cyanheads/mcp-ts-core` was updated, do a deeper pass beyond what the `changelog` skill covers. The framework ships a **directory-based changelog** grouped by minor series (`.x` semver-wildcard convention) — one file per released version at `node_modules/@cyanheads/mcp-ts-core/changelog/<major.minor>.x/<version>.md`. Read only the files between old and new rather than scanning a monolithic file.

Example — `0.5.2 → 0.5.4` means reading two new version files:

- `node_modules/@cyanheads/mcp-ts-core/changelog/0.5.x/0.5.3.md`
- `node_modules/@cyanheads/mcp-ts-core/changelog/0.5.x/0.5.4.md`

Cross-series updates span multiple directories — e.g., `0.4.1 → 0.5.2` reads `0.5.x/0.5.0.md`, `0.5.x/0.5.1.md`, `0.5.x/0.5.2.md`. Enumerate the series directories under `node_modules/@cyanheads/mcp-ts-core/changelog/` to find the relevant files.

If the per-version directory isn't present (pre-0.5.5 releases, or downstream package that hasn't adopted the convention), fall back to the monolithic rollup at `node_modules/@cyanheads/mcp-ts-core/CHANGELOG.md` and extract the relevant sections manually.

Scan specifically for:

| Area | Adoption Check |
|:-----|:---------------|
| New `/errors` surface — factories, typed contracts (`errors[]` + `ctx.fail`), `httpErrorFromResponse` | Replace ad-hoc `new McpError(...)` with factories; declare `errors: [...]` on tools that surface domain-specific failure modes; route declared throws through `ctx.fail(reason, …)` so the conformance lint is happy |
| Existing factory choice — semantic audit | Beyond factory-vs-`new McpError`: audit each `throw factory(...)` against intent. `invalidParams` (-32602) is for malformed JSON-RPC params (wrong-shape post-Zod is rare); semantic post-shape validation should use `validationError` (-32007). `notFound` for missing entities, `conflict` for state collisions, `unauthorized` vs `forbidden` for unauth vs scope-denied. Wrong codes degrade `mcp_error_classified_code` observability and break client retry logic — fix during this pass even if not adopting contracts yet. |
| New utilities in `/utils` | Identify any that supersede local helper code |
| New context capabilities | Added `ctx.*` methods worth adopting |
| Provider/service APIs | Updates to `OpenRouterProvider`, `SpeechService`, `GraphService`, etc. |
| Deprecations | Migrate now, before the next breaking release |
| Config changes | New env vars, renamed keys, changed defaults |
| Linter rules | New definition-lint rules that may now flag existing tools/resources |
| New or materially-changed skills | Note new skills or workflow changes (renamed steps, new checklist items) worth surfacing at end-of-run. Don't auto-invoke — some skills (e.g. `security-pass`) are user-triggered. The per-version changelog entries (e.g. 0.6.14 calling out `skills/security-pass/ (v1.0)`) name what changed. |
| New template-scaffolded files | Compare `templates/` in the package against the project root. Files that `init` would create for a new project but don't exist in this project are adoption candidates — create them with project-specific values (version, name, description, env vars from `server.json`). Examples: `manifest.json`, `.mcpbignore`, `.codex-plugin/`, `.claude-plugin/`. Skip files the project has intentionally opted out of (documented in CLAUDE.md/AGENTS.md or a code comment). |
| Changelog `agent-notes` | Read `agent-notes` frontmatter from each new per-version changelog file — these carry release-specific adoption instructions for downstream consumers (new files to create, fields to populate, one-time migration steps). Apply them alongside other adoption work in Step 6. |

Cross-reference each finding against the server's code. Collect adoption opportunities for Step 6.

**Template review.** The framework also ships `templates/CLAUDE.md` and `templates/AGENTS.md` as scaffolding for consumer agent protocol files. The consumer's `CLAUDE.md`/`AGENTS.md` was copied at init time and has since diverged (local customizations, echo replacements, server-specific sections). Read the upstream template fresh at `node_modules/@cyanheads/mcp-ts-core/templates/CLAUDE.md`.

Read the upstream template end-to-end, mentally comparing against the current `CLAUDE.md`/`AGENTS.md`. Apply framework-authored updates directly — new skill references in the skills table, new entries in the "What's Next?" section, updated convention callouts, clarified patterns. These are factual updates, not taste decisions; the consumer's agent protocol file is meant to track the framework's. Only surface a decision when a template change conflicts with a section the consumer has intentionally customized — a section is "intentionally customized" when it contains server-specific domain context, bespoke checklists, or content that doesn't originate from the template. In that case, note the conflict and ask.

### 5. Sync project skills and scripts

Skills flow in two hops: package → project `skills/` → agent directories. Framework scripts flow in one: package → project `scripts/`. Both drift silently unless resynced.

**Phase A — Package → Project `skills/`**

1. **Package** — `node_modules/@cyanheads/mcp-ts-core/skills/` (canonical source)
2. **Project** — `skills/` at project root (working copy; may contain local overrides or server-specific skills)

Procedure:

1. List all skill directories in `node_modules/@cyanheads/mcp-ts-core/skills/`
2. For each skill with `metadata.audience: external` in its `SKILL.md` frontmatter:
   - If missing in project `skills/`, copy the full directory
   - If present, compare `metadata.version` — replace if the package version is newer
   - If the local version is equal or newer, skip (local override)
3. Leave skills in `skills/` that lack `metadata.audience: external` untouched — they're server-specific or sourced elsewhere, not framework-managed.
4. **Prune framework skills deleted upstream.** A skill in `skills/` that *carries* `metadata.audience: external` but is **absent** from the package was removed upstream (e.g. `migrate-mcp-ts-template`, removed in 0.9.12) and lingers because sync was previously add/update-only. Delete it from `skills/` (and from the agent mirrors in Phase B). The `audience: external` marker is the provenance: it scopes the prune to framework-managed skills, so a server's own skills — which never carry it — are never touched. Before deleting, scan the skill for local edits worth keeping; if any exist, reconcile or surface them rather than discarding silently.

**Skill diffs are adoption signal, not just sync output.** After replacing files in `skills/`, run `git diff skills/` to read what changed. Updated skill bodies describe new patterns, refined workflows, or new conventions — apply them to the codebase in Step 6 the same way you'd apply a framework API addition. The file copy is the *trigger*, not the work. The work is what the updated skill now says to do.

**Phase B — Project `skills/` → Agent directories**

The `setup` skill instructs consumers to copy `skills/*` into their agent's skill directory at init time. Those copies go stale unless re-synced. Detect which agent directories exist and propagate:

| Agent | Directory |
|:------|:----------|
| Claude Code | `.claude/skills/` |
| Generic / shared | `.agents/skills/` |
| Codex | `.codex/skills/` |
| Cursor | `.cursor/skills/` |
| Windsurf | `.windsurf/skills/` |

For each agent directory that exists:

1. For every directory in project `skills/`, copy it into the agent dir (overwrite on match, add if missing)
2. Do **not** delete skills in the agent dir that aren't in project `skills/` — they may be general-purpose skills sourced elsewhere (e.g., `code-security`, `cloudflare`, `changelog`). **Exception:** a framework skill pruned in Phase A step 4 — delete that same-named directory from each agent dir too. Match by the specific name you just removed, never by a blanket "absent from `skills/`" sweep (which would catch the externally-sourced skills above).

If no agent directory exists, skip Phase B — the project hasn't opted in to per-agent skill copies.

**Phase C — Package framework files → Project**

Two categories of framework-authored files ship into consumer projects and drift silently as the framework updates them. Both follow the same hash-compare-and-overwrite mechanic.

**Scripts** — `init` scaffolds a fixed set that underpin `bun run build`, `bun run devcheck`, `bun run lint:mcp`, `bun run tree`, and the changelog build. Iterate the package's shipped scripts directory:

```bash
for src in node_modules/@cyanheads/mcp-ts-core/scripts/*.ts; do
  s=$(basename "$src")
  dst="scripts/$s"
  if [ ! -f "$dst" ]; then
    cp "$src" "$dst"
    echo "added: $s"
  elif ! cmp -s "$src" "$dst"; then
    cp "$src" "$dst"
    echo "updated: $s"
  fi
done
```

Scripts in `scripts/` that aren't present in the package directory are project-specific (custom deploy, codegen, etc.) — leave them alone. The package's `files:` field gates what ships into `node_modules/.../scripts/`, so enumerating that directory is the canonical "shipped scripts" set.

**Pristine reference files** — files explicitly documented as "never edit, rename, or move." The framework keeps the authoritative copy under `templates/`; the consumer's copy must track upstream as the format evolves (new frontmatter fields, section reorderings, etc.). Fixed src→dst mapping:

| Source (in package) | Destination (in project) |
|:--|:--|
| `templates/changelog/template.md` | `changelog/template.md` |

Apply the same compare-and-overwrite logic. Add new entries here only when a template is explicitly documented as pristine in the framework's CLAUDE.md/AGENTS.md or its own header.

If the consumer customized a framework script or pristine reference (against guidance), the overwrite discards those changes. After the sync runs, diff `scripts/` and the affected template paths to surface replacements — review before committing. If a specific local customization needs to be preserved, revert that file using your git tools.

**Report** which skills were added/updated in Phase A (with version deltas), which agent directories were refreshed in Phase B, and which scripts and pristine reference files were resynced in Phase C. The user needs to know what new guidance and tooling is now in play.

### 6. Adopt changes in the codebase

Apply the findings from Steps 3 and 4. Framework changes and third-party library changes have different adoption defaults — the asymmetry is deliberate.

**Framework changes (`@cyanheads/mcp-ts-core`) — auto-adopt every applicable site, in this pass.**

The consumer opted into the framework; its templates, skills, scripts, linter rules, conventions, and new APIs that supersede local code are authoritative. Adopt them now — not as a follow-up.

- **Synced skill content from Phase A** — `git diff skills/` for every skill that was updated. Each updated body is new framework guidance; apply it to matching surfaces in this server. Examples: `add-tool` gains a section on output formatting → audit existing tool definitions against that section; `api-errors` documents a new contract pattern → adopt across error surfaces; `security-pass` adds a new check → run it against the surface. Skill updates aren't metadata.
- **Breaking changes** — fix call sites. Not optional.
- **Deprecations** — migrate now, while context is fresh.
- **New linter rules** — if the rule now flags existing code, fix the code; don't silence the rule.
- **New utilities that supersede local code** — swap them in. The point of the framework is to centralize. This applies even when the local helper has richer messages or branch handling — port the domain detail onto the framework path; don't leave the local helper as-is. (E.g., `httpErrorFromResponse` replacing a project-local `throwForStatus`: keep the per-route message map, but route it through the framework utility.)
- **New conventions** (template changes, new config keys, renamed env vars) — adopt and update `.env.example`, server config schema, `server.json`, and README if user-facing.
- **New patterns that match existing surfaces** — refactor *every* matching site in this pass. Examples: typed error contracts (`errors[]` + `ctx.fail`) on tools that already throw domain-specific failures; factory adoption (`notFound()`, `validationError()`, …) replacing ad-hoc `new McpError(...)`; new logging/observability hooks supplanting bespoke logging. If the framework added a pattern that fits N tools/services, do all N — partial adoption fragments the surface and rots faster.
- **New framework features that don't match existing use cases** — skip. These are for future features, not retroactive refactors. "Don't match" means *the surface doesn't exist in this server* (e.g., a new Speech API in a non-speech server) — not "I'd have to touch a few files."

**Hard rule — invalid framework deferrals.**

| ❌ Not a valid reason to defer | ✅ Valid reason to defer |
|:-------------------------------|:-------------------------|
| "Larger change than fits this pass" | Code-commented or `CLAUDE.md`/`AGENTS.md`-documented local override that intentionally diverges from the framework convention |
| "Marginal benefit / leaving as-is" | Breaking change with multiple migration paths that need user input |
| "Per-tool refactor — worth doing as a focused follow-up" | Feature genuinely doesn't apply (the surface doesn't exist in this server) |
| "Existing helper has rich domain messages we'd lose" | — (port the messages onto the framework path) |
| "Skill was synced, the file change is the adoption" | — (the file copy is the trigger; the adoption is applying the new guidance to the code) |

If you find yourself writing the left-column phrasing in Step 8's "Open decisions", stop and adopt it instead. Cost/benefit reasoning belongs to third-party changes only.

**Third-party library changes — default cost/benefit.**

- Read the changelog findings from Step 3, assess impact against actual call sites in `src/`.
- Adopt when the change is a clear win (performance, correctness, removed deprecation warning, smaller surface).
- Skip when marginal — a new convenience API isn't a reason to touch working code.
- If the library added a feature the server could use, note it but don't refactor speculatively.

### 7. Rebuild and verify

```bash
bun run rebuild
bun run devcheck
bun run test
```

`rebuild` (clean + build) catches API surface and type-alignment issues that `devcheck` alone may miss — module resolution, path aliases, post-build processing. `devcheck` includes `bun audit` and `bun outdated`, so no separate audit step is needed.

In **Mode B**, the user already ran rebuild + test before invoking this skill, but run them again here — Step 6 made code changes that need re-verification.

Fix anything that fails. Re-run until clean.

**Transitive advisory triage.** If `bun audit` (inside devcheck) reports a vulnerability in a transitive dep, run `bun run audit:refresh` before treating it as real. Bun's `bun update` is sticky on transitive resolutions — it keeps lockfile entries even when a parent's range allows a newer patched version. `audit:refresh` deletes `bun.lock`, reinstalls, and re-audits; if the advisory disappears, it was a stale-lockfile false positive (commit the refreshed lockfile). If it survives, it's real — patch via `package.json` `overrides` or nudge upstream.

### 8. Summary

Present a concise numbered summary to the user:

1. **Updated packages** — short list with version deltas (N total)
2. **Breaking changes handled** — call sites fixed
3. **Features adopted** — new framework APIs now in use
4. **Skills synced** — added/updated with versions (Phase A) and agent directories refreshed (Phase B)
5. **New/changed skills available** — skills that appeared in Phase A for the first time or had materially-changed step sequences. Frame as "consider running when the time is right" rather than immediate actions; the user decides when to invoke them.
6. **Open decisions** — genuinely ambiguous items only. Valid: breaking changes with multiple migration paths needing user input, framework changes that conflict with a code-commented or `CLAUDE.md`/`AGENTS.md`-documented local override, third-party adoptions where cost/benefit is close. **Not valid:** framework adoptions deferred for scope, effort, or marginal-benefit reasoning — those were already adopted in Step 6 and belong under "Features adopted." If this section is empty, that's the expected outcome of a clean framework upgrade.
7. **Status** — rebuild / devcheck / test results

## Checklist

- [ ] Update applied (`bun update --latest`) — Mode A, or already done by user — Mode B
- [ ] Skill-version paradox checked — if package maintenance skill version > running version, Phase A run first and skill re-invoked
- [ ] `changelog` skill invoked for each updated package
- [ ] Framework CHANGELOG reviewed if `@cyanheads/mcp-ts-core` was updated
- [ ] Framework `CLAUDE.md`/`AGENTS.md` template reviewed; applicable updates applied or conflicts surfaced
- [ ] Step 6 complete — all applicable framework adoption sites updated; third-party adoption decisions recorded
- [ ] Project `skills/` synced from package (Phase A), with a change report
- [ ] Agent skill directories (`.claude/skills/`, `.agents/skills/`, etc.) refreshed from project `skills/` (Phase B)
- [ ] Framework `scripts/` and pristine reference files resynced from package via content-hash compare (Phase C), with a change report; diffs reviewed before committing
- [ ] `bun run rebuild` succeeds (re-run after Step 6, even in Mode B)
- [ ] `bun run devcheck` passes (includes audit + outdated)
- [ ] `bun run test` passes
- [ ] Numbered summary presented to user

Related Skills

tool-defs-analysis

8
from cyanheads/pubchem-mcp-server

Read-only audit of MCP definition language across an existing surface — tools, resources, prompts. Walks every definition file and checks 12 categories the LLM reads to decide whether and how to call: voice & tense, internal leaks, audience leaks, defaults, recovery hints, output descriptions, cross-references, sparsity, examples, structure, mutator observability, unit-bearing numeric names. Produces grouped findings with file:line citations and a numbered options list. Use during polish, after a refactor, or before a release. Complements `field-test` (behavior testing) and `security-pass` (security audit).

setup

8
from cyanheads/pubchem-mcp-server

Post-init orientation for an MCP server built on @cyanheads/mcp-ts-core. Use after running `@cyanheads/mcp-ts-core init` to understand the project structure, conventions, and skill sync model. Also use when onboarding to an existing project for the first time.

security-pass

8
from cyanheads/pubchem-mcp-server

Review an MCP server for common security gaps: LLM-facing surfaces as injection vector (tools, resources, prompts, descriptions), scope blast radius, destructive ops without consent, upstream auth shape, input sinks (URL / path / roots / shell / sampling / schema strictness / ReDoS), tenant isolation, leakage through errors and telemetry, unbounded resources, and HTTP-mode deployment surface. Use before a release, after a batch of handler changes, or when the user asks for a security review, audit, or hardening pass. Produces grouped findings and a numbered options list.

report-issue-local

8
from cyanheads/pubchem-mcp-server

File a bug or feature request against this MCP server's own repo. Use for server-specific issues — tool logic, service integrations, config problems, or domain bugs that aren't caused by the framework.

report-issue-framework

8
from cyanheads/pubchem-mcp-server

File a bug or feature request against @cyanheads/mcp-ts-core when you hit a framework issue. Use when a builder, utility, context method, or config behaves contrary to the documented API — not for server-specific application bugs.

release-and-publish

8
from cyanheads/pubchem-mcp-server

Ship a release end-to-end across every registry the project targets (npm, MCP Registry, GitHub Releases for `.mcpb` bundles, GHCR). Runs the final verification gate, pushes commits and tags, then publishes to each applicable destination. Assumes git wrapup (version bumps, changelog, commit, annotated tag) is already complete — this skill is the post-wrapup publish workflow. Retries transient network failures on publish steps; halts with a partial-state report when retries are exhausted or the failure is terminal.

polish-docs-meta

8
from cyanheads/pubchem-mcp-server

Finalize documentation and project metadata for a ship-ready MCP server. Use after implementation is complete, tests pass, and devcheck is clean. Safe to run at any stage — each step checks current state and only acts on what still needs work.

orchestrations

8
from cyanheads/pubchem-mcp-server

Pick and run a multi-phase workflow that chains foundational task skills (`git-wrapup`, `release-and-publish`, `maintenance`, `field-test`, `setup`, etc.) end-to-end. Routes user intent to a workflow file under `workflows/` — greenfield builds, maintenance + release, field-test + fix, or known-work + release. Single source for the universal rules (no commits without authorization, no destructive git, no marketing language), the orchestrator posture (own the goal, ground sub-agents in primary sources, verify against the goal), and the sub-agent strategy (orient block, parallel fanout, isolation, normalization) that apply across every workflow. Sub-agents are an optional capability — workflows run linearly when fanout isn't available.

git-wrapup

8
from cyanheads/pubchem-mcp-server

Land working-tree changes as logical commits — the work grouped by concern, topped by a release commit (version bump, changelog, regenerated artifacts) and an annotated tag. Verify, commit, tag. Stops at "committed and tagged locally" — no push, no publish. The release-and-publish skill picks up from here. Distilled from the git_wrapup_instructions protocol.

field-test

8
from cyanheads/pubchem-mcp-server

Exercise tools, resources, and prompts against a live HTTP server via MCP JSON-RPC over curl. Starts the server, surfaces the catalog, runs real and adversarial inputs, and produces a tight report with concrete findings and numbered follow-up options. Use after adding or modifying definitions, or when the user asks to test, try out, or verify their MCP surface.

devcheck

8
from cyanheads/pubchem-mcp-server

Lint, format, typecheck, and verify the project is clean. Use after making changes, before committing, or when the user asks to verify quality.

design-mcp-server

8
from cyanheads/pubchem-mcp-server

Design the tool surface, resources, and service layer for a new MCP server. Use when starting a new server, planning a major feature expansion, or when the user describes a domain/API they want to expose via MCP. Produces a design doc at docs/design.md that drives implementation.