@cyanheads/interpro-mcp-server 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +39 -14
- package/CLAUDE.md +39 -14
- package/Dockerfile +9 -1
- package/README.md +92 -107
- package/changelog/0.1.x/0.1.3.md +24 -0
- package/changelog/0.2.x/0.2.0.md +31 -0
- package/dist/config/server-config.d.ts +13 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +19 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-find-proteins-by-domain.tool.d.ts +89 -2
- package/dist/mcp-server/tools/definitions/interpro-find-proteins-by-domain.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-find-proteins-by-domain.tool.js +80 -5
- package/dist/mcp-server/tools/definitions/interpro-find-proteins-by-domain.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-get-entry.tool.d.ts +59 -0
- package/dist/mcp-server/tools/definitions/interpro-get-entry.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-get-entry.tool.js +139 -5
- package/dist/mcp-server/tools/definitions/interpro-get-entry.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-get-protein-domains.tool.d.ts +21 -2
- package/dist/mcp-server/tools/definitions/interpro-get-protein-domains.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-get-protein-domains.tool.js +99 -23
- package/dist/mcp-server/tools/definitions/interpro-get-protein-domains.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-get-scan-result.tool.d.ts +133 -0
- package/dist/mcp-server/tools/definitions/interpro-get-scan-result.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/interpro-get-scan-result.tool.js +128 -0
- package/dist/mcp-server/tools/definitions/interpro-get-scan-result.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/interpro-get-structure-domains.tool.d.ts +171 -0
- package/dist/mcp-server/tools/definitions/interpro-get-structure-domains.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/interpro-get-structure-domains.tool.js +290 -0
- package/dist/mcp-server/tools/definitions/interpro-get-structure-domains.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/interpro-list-reference.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/interpro-list-reference.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-scan-sequence.tool.d.ts +168 -0
- package/dist/mcp-server/tools/definitions/interpro-scan-sequence.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/interpro-scan-sequence.tool.js +187 -0
- package/dist/mcp-server/tools/definitions/interpro-scan-sequence.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/interpro-search-entries.tool.d.ts +6 -0
- package/dist/mcp-server/tools/definitions/interpro-search-entries.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/interpro-search-entries.tool.js +11 -2
- package/dist/mcp-server/tools/definitions/interpro-search-entries.tool.js.map +1 -1
- package/dist/services/interpro/format.d.ts.map +1 -1
- package/dist/services/interpro/format.js +8 -17
- package/dist/services/interpro/format.js.map +1 -1
- package/dist/services/interpro/http-adapter.d.ts +11 -2
- package/dist/services/interpro/http-adapter.d.ts.map +1 -1
- package/dist/services/interpro/http-adapter.js +67 -9
- package/dist/services/interpro/http-adapter.js.map +1 -1
- package/dist/services/interpro/interpro-service.d.ts +1 -1
- package/dist/services/interpro/interpro-service.d.ts.map +1 -1
- package/dist/services/interpro/interpro-service.js +6 -24
- package/dist/services/interpro/interpro-service.js.map +1 -1
- package/dist/services/interpro/reference.d.ts.map +1 -1
- package/dist/services/interpro/reference.js +23 -2
- package/dist/services/interpro/reference.js.map +1 -1
- package/dist/services/interpro/schemas.d.ts +16 -0
- package/dist/services/interpro/schemas.d.ts.map +1 -1
- package/dist/services/interpro/schemas.js +13 -0
- package/dist/services/interpro/schemas.js.map +1 -1
- package/dist/services/interpro/structure-schemas.d.ts +116 -0
- package/dist/services/interpro/structure-schemas.d.ts.map +1 -0
- package/dist/services/interpro/structure-schemas.js +74 -0
- package/dist/services/interpro/structure-schemas.js.map +1 -0
- package/dist/services/sequence-scan/scan-output.d.ts +94 -0
- package/dist/services/sequence-scan/scan-output.d.ts.map +1 -0
- package/dist/services/sequence-scan/scan-output.js +174 -0
- package/dist/services/sequence-scan/scan-output.js.map +1 -0
- package/dist/services/sequence-scan/scan-schemas.d.ts +112 -0
- package/dist/services/sequence-scan/scan-schemas.d.ts.map +1 -0
- package/dist/services/sequence-scan/scan-schemas.js +97 -0
- package/dist/services/sequence-scan/scan-schemas.js.map +1 -0
- package/dist/services/sequence-scan/sequence-scan-service.d.ts +119 -0
- package/dist/services/sequence-scan/sequence-scan-service.d.ts.map +1 -0
- package/dist/services/sequence-scan/sequence-scan-service.js +453 -0
- package/dist/services/sequence-scan/sequence-scan-service.js.map +1 -0
- package/dist/services/sequence-scan/sequence.d.ts +32 -0
- package/dist/services/sequence-scan/sequence.d.ts.map +1 -0
- package/dist/services/sequence-scan/sequence.js +63 -0
- package/dist/services/sequence-scan/sequence.js.map +1 -0
- package/package.json +10 -7
- package/server.json +18 -4
- package/skills/interpro-guide/SKILL.md +72 -0
package/AGENTS.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/interpro-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.2.0
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` ^2.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.4.0
|
|
8
8
|
**Zod:** ^4.6.7
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -48,7 +48,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
48
48
|
|
|
49
49
|
### Tool
|
|
50
50
|
|
|
51
|
-
Abridged from `src/mcp-server/tools/definitions/interpro-get-entry.tool.ts`. All
|
|
51
|
+
Abridged from `src/mcp-server/tools/definitions/interpro-get-entry.tool.ts`. All nine tools share this shape: a service call through `service.begin(ctx)`, `ctx.enrich` for notices, a per-tool `errors` contract, and the shared `formatInterpro` formatter.
|
|
52
52
|
|
|
53
53
|
```ts
|
|
54
54
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
@@ -96,7 +96,7 @@ export const interproGetEntry = tool('interpro_get_entry', {
|
|
|
96
96
|
});
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
There are no resources or prompts
|
|
99
|
+
There are no resources or prompts. The InterPro API is keyless; the one server-specific environment variable, optional `INTERPRO_SCAN_EMAIL` (parsed in `src/config/server-config.ts`), is the contact address the EBI Job Dispatcher requires for InterProScan submissions. Unset, `interpro_scan_sequence` still serves precalculated matches and fails other sequences as `scan_not_configured`; the hosted instance leaves it unset. The scan tools (`interpro_scan_sequence`, `interpro_get_scan_result`) run through `src/services/sequence-scan/`, outside the InterPro pacer, and `interpro_scan_sequence` is the only tool that is not read-only. `interpro_get_structure_domains` lifts each match's nested chain records into top-level `structures[]` joined by `entry` to stay inside the depth-8 parity walker, and its numbering contract (chain `start`/`end` beside author `auth_start`/`auth_end`, UniProt positions) is retained verbatim. Optional `proteomeId` on discovery joins the route after `taxonId` and binds to the cursor scope only when present. Search/member pages clamp positive integer limits to 100, discovery to 50, with default 20 and composed notices. GO filters require the InterPro source and accept either `goTerm` or `goCategory`, never both; member recovery follows `member_databases` or `integratedInto`. Entry `sections` selects named metadata while retaining core and unknown fields; explicit `overlapLimit` enables whole-record paging. Retained descriptions gain readable `descriptionText` through `htmlparser2`, alongside unchanged raw descriptions and annotation flags. Protein maps append requested residue rules after matches and extra features, preserving complete records and old cursor scopes when the new flag is absent/false. Discovery requests native fragment status on every page; optional `architectureId` adds native IDA grouping and explicit entry/taxon detail availability without inventing missing arrays. Bind only explicit selections to cursor scope and preserve unknown upstream values.
|
|
100
100
|
|
|
101
101
|
### Server identity and instructions
|
|
102
102
|
|
|
@@ -106,9 +106,13 @@ There are no resources or prompts and no server-specific environment variables:
|
|
|
106
106
|
await createApp({
|
|
107
107
|
name: 'interpro-mcp-server',
|
|
108
108
|
title: 'interpro-mcp-server',
|
|
109
|
-
tools: [/*
|
|
109
|
+
tools: [/* nine definitions */],
|
|
110
110
|
sessionMode: 'stateless',
|
|
111
|
-
|
|
111
|
+
skills: 'skills',
|
|
112
|
+
setup() {
|
|
113
|
+
initInterproService();
|
|
114
|
+
initSequenceScanService(getServerConfig().scanEmail);
|
|
115
|
+
},
|
|
112
116
|
teardown() { disposeInterproService(); },
|
|
113
117
|
instructions: '…',
|
|
114
118
|
});
|
|
@@ -182,12 +186,15 @@ See framework CLAUDE.md and the `api-errors` skill for the full auto-classificat
|
|
|
182
186
|
```text
|
|
183
187
|
src/
|
|
184
188
|
index.ts # createApp() entry point
|
|
189
|
+
config/
|
|
190
|
+
server-config.ts # INTERPRO_SCAN_EMAIL parsing (lazy, validated at startup)
|
|
185
191
|
services/
|
|
186
192
|
interpro/
|
|
187
193
|
interpro-service.ts # Paced, cancellable request boundary (init/accessor pattern)
|
|
188
|
-
http-adapter.ts # node:https HTTP/1.1 transport with 204 handling
|
|
194
|
+
http-adapter.ts # node:https HTTP/1.1 transport with 204 handling; also carries the scan tools' Matches API and Job Dispatcher calls
|
|
189
195
|
routing.ts # Accession → database routing, fixed-origin URL building
|
|
190
196
|
schemas.ts # Wire and output Zod schemas
|
|
197
|
+
structure-schemas.ts # PDB ID and chain validation, structure and chain-record schemas
|
|
191
198
|
cursors.ts # Opaque cursor envelopes
|
|
192
199
|
budget.ts # 100,000-byte response budget and whole-item fitting
|
|
193
200
|
relationships.ts # Clan relationship-graph slicing
|
|
@@ -195,9 +202,14 @@ src/
|
|
|
195
202
|
format.ts # Shared content[] formatter
|
|
196
203
|
description-text.ts # Readable HTML fragment projection for entry detail
|
|
197
204
|
upstream-errors.ts # Shared upstream error contract rows
|
|
205
|
+
sequence-scan/
|
|
206
|
+
sequence.ts # Sequence parsing and the UniParc MD5 digest
|
|
207
|
+
scan-schemas.ts # Matches API, Job Dispatcher, and match-record schemas
|
|
208
|
+
sequence-scan-service.ts # Precalculated lookup, job submission and polling, in-flight cap
|
|
209
|
+
scan-output.ts # Shared scan output schema and match segmentation
|
|
198
210
|
mcp-server/
|
|
199
211
|
tools/definitions/
|
|
200
|
-
interpro-[name].tool.ts #
|
|
212
|
+
interpro-[name].tool.ts # Nine tool definitions
|
|
201
213
|
tests/
|
|
202
214
|
services/ # Service, adapter, and budget tests
|
|
203
215
|
tools/ # Tool contract tests
|
|
@@ -218,9 +230,18 @@ tests/
|
|
|
218
230
|
|
|
219
231
|
## Skills
|
|
220
232
|
|
|
221
|
-
|
|
233
|
+
Two skill trees live at the project root, written for different readers:
|
|
234
|
+
|
|
235
|
+
| Tree | For | Written by |
|
|
236
|
+
|:-----|:----|:-----------|
|
|
237
|
+
| `framework-skills/` | The agent developing this server — framework skills (`metadata.audience: external`) plus any development-time skills of the server's own | `init` and the `maintenance` sync (framework skills); you (your own) |
|
|
238
|
+
| `skills/` | The agents that install the server and call its tools — tool chains, identifier sources, gates | You, deliberately, with the `add-skill` skill. Absent by default; usually none is needed |
|
|
239
|
+
|
|
240
|
+
Development skills are modular instructions. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry. Their directory is deliberately not `skills/`: Claude Code and Codex auto-load a plugin's root `skills/`, so a server that ships `.claude-plugin/` or `.codex-plugin/` would hand them to every agent that installs it.
|
|
241
|
+
|
|
242
|
+
A published skill in root `skills/` reaches plugin installs and the `.mcpb` bundle as-is, ships in the npm package and the Docker image, and reaches MCP clients when the server opts in with `createApp({ skills: 'skills' })`. `lint:packaging` validates the tree. This server publishes one, `skills/interpro-guide/SKILL.md` (identifier chains, gates, and chain/author/UniProt numbering), served with `skills: 'skills'`.
|
|
222
243
|
|
|
223
|
-
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
244
|
+
**Agent skill directory:** Copy `framework-skills/` into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
224
245
|
|
|
225
246
|
Available skills:
|
|
226
247
|
|
|
@@ -232,6 +253,7 @@ Available skills:
|
|
|
232
253
|
| `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
|
|
233
254
|
| `add-resource` | Scaffold a new resource definition |
|
|
234
255
|
| `add-prompt` | Scaffold a new prompt definition |
|
|
256
|
+
| `add-skill` | Author a skill the server publishes in root `skills/` for the agents that use it — when one earns its place, structure, validation, delivery |
|
|
235
257
|
| `add-service` | Scaffold a new service integration |
|
|
236
258
|
| `add-test` | Scaffold test file for a tool, resource, or service |
|
|
237
259
|
| `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
|
|
@@ -279,7 +301,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
279
301
|
| `bun run audit:fix` | `bun audit fix` — upgrade vulnerable packages to the lowest safe version within existing ranges (`--dry-run` previews, `--latest` rewrites ranges). First response when `devcheck` flags a transitive advisory; then `bun update <name>`, then `bun dedupe` |
|
|
280
302
|
| `bun run audit:refresh` | Delete `bun.lock` and reinstall. Last resort after `audit:fix`, `bun update <name>`, and `bun dedupe` — re-resolves every ranged dep (the framework pin included) and rewrites the lockfile as `lockfileVersion: 2` |
|
|
281
303
|
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
282
|
-
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity (run by devcheck) |
|
|
304
|
+
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, `.mcpbignore` coverage, plugin manifests, the published `skills/` tree (run by devcheck) |
|
|
283
305
|
| `bun run list-skills` | Print the skill registry |
|
|
284
306
|
| `bun run tree` | Generate directory structure doc |
|
|
285
307
|
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
@@ -295,7 +317,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
295
317
|
| `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
296
318
|
| `bun run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
297
319
|
|
|
298
|
-
**Waived `devcheck` warnings.**
|
|
320
|
+
**Waived `devcheck` warnings.** The owner waived `format-parity-depth-limit` for the `…fragments[].start`, `…fragments[].end`, and `…fragments[].dc-status` output fields of `interpro_find_proteins_by_domain` and `interpro_get_protein_domains`, plus discovery's containing path `proteins[].entries[].entry_protein_locations[].fragments[]`. The architecture union moves discovery's three diagnostics to that array, so the current schema emits four warnings. These finite nested records exceed the framework's depth-8 parity walker; tests prove both surfaces retain them, pending [cyanheads/mcp-ts-core#531](https://github.com/cyanheads/mcp-ts-core/issues/531). Don't flatten or weaken the schema or add suppressions. Any warning outside these exact paths still blocks shipping.
|
|
299
321
|
|
|
300
322
|
**CI is one file.** `.github/workflows/codeql.yml` (scaffolded) is the only GitHub Actions workflow: CodeQL is GitHub-owned end to end, and the file runs only while the repo's CodeQL *default setup* is turned off. Verification — `devcheck`, tests, the release gates — runs locally; don't add a workflow that re-runs it.
|
|
301
323
|
|
|
@@ -303,7 +325,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
303
325
|
|
|
304
326
|
## Bundling
|
|
305
327
|
|
|
306
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips
|
|
328
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. `mcpb pack` reads `.mcpbignore`, not `.gitignore`, so every root path the bundle must not ship — source, tests, docs, caches, logs, agent docs, plugin manifests, gitignored local files — needs a root-anchored line there (`/docs/`, never `docs/`, which also strips `node_modules/*/docs/`); `lint:packaging` names each missing or unanchored line. Root `skills/` ships on purpose. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips four classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`framework-skills/`, `skills/`, `.claude/`, `.agents/`, `SKILL.md`); platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on; node-gyp build output beside a `binding.gyp` (`config.gypi`, Makefiles, `obj.target/`, `.deps/`, object files and debug symbols), which records the packing machine's paths — compiled `*.node` addons stay; and build-only package files — the framework's `changelog/`, `scripts/`, `templates/`, `CLAUDE.md`, `AGENTS.md`, and config bases (`biome.json`, `vitest.config.base.mjs`, `config/tsconfig.base.json`), and `better-sqlite3`'s `deps/` and `src/` C sources. A server using DataCanvas therefore ships a portable bundle without the DuckDB native — `@duckdb/node-api` is an optional peer loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
307
329
|
|
|
308
330
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match, that every `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.X}"` (the host substitutes nothing else — `"${X}"` reaches the server as that literal string), and that an optional string option carries `"default": ""`.
|
|
309
331
|
|
|
@@ -370,7 +392,10 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
370
392
|
- [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
|
|
371
393
|
- [ ] Registered in `createApp()` arrays (directly or via barrel exports)
|
|
372
394
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
395
|
+
- [ ] `plugin.json` + `mcp.json` (Agent Plugins 1.0.0 — read by Codex, Cursor, GitHub Copilot, VS Code, Kiro) populated — `plugin.json` `name` = the unscoped repo name (lowercase `a-z`, `0-9`, `-`, `.` only); `version`, `description`, `author`, `homepage`, `repository`, `license`, `keywords` from `package.json`; no other top-level field, `extensions` included. `mcp.json` holds one `"type": "stdio"` entry keyed by the unscoped name, `npx -y <full package name>`, and the same fixed `env` as `.codex-plugin/mcp.json`. Neither file carries a user-supplied variable (no `""`, no `${…}` besides `${PLUGIN_ROOT}`/`${PLUGIN_DATA}`): keys reach Codex through `.codex-plugin/mcp.json` `env_vars`, which works only while `.codex-plugin/plugin.json` keeps `"mcpServers": "./.codex-plugin/mcp.json"`
|
|
373
396
|
- [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = the unscoped repo name (never the npm scope — `lint:packaging` enforces this); `interface.shortDescription` from `package.json` description
|
|
374
397
|
- [ ] `.codex-plugin/mcp.json` updated — server name key is the unscoped repo name; every user-supplied variable (API key, contact email, instance URL) is listed in `env_vars` so Codex forwards it from the user's environment. Never write `"KEY": ""` into `env` — an empty value replaces the user's exported key and is read as unset
|
|
375
398
|
- [ ] `.claude-plugin/plugin.json` populated — `name`, `version`, `description`, `author`, `repository`, `license`, `keywords` from `package.json`; inline `mcpServers` entry keyed by the unscoped repo name. Every user-supplied variable is declared under `userConfig` (`type`, `title`, `description`; `sensitive: true` for keys and tokens; `required: true` or `default: ""`) and referenced from `env` as `"KEY": "${user_config.<option>}"` — mirror the `user_config` block in `manifest.json`. Never write `"KEY": ""` into `env`
|
|
399
|
+
- [ ] Any new root dev path has a root-anchored line in `.mcpbignore`; `bun run bundle` and `lint:packaging` pass
|
|
400
|
+
- [ ] If the server publishes a skill in root `skills/`: `lint:packaging` passes, and `field-test` verified every gate and identifier claim in it against live tool behavior
|
|
376
401
|
- [ ] `npm run devcheck` passes
|
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/interpro-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.2.0
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` ^2.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.4.0
|
|
8
8
|
**Zod:** ^4.6.7
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -48,7 +48,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
48
48
|
|
|
49
49
|
### Tool
|
|
50
50
|
|
|
51
|
-
Abridged from `src/mcp-server/tools/definitions/interpro-get-entry.tool.ts`. All
|
|
51
|
+
Abridged from `src/mcp-server/tools/definitions/interpro-get-entry.tool.ts`. All nine tools share this shape: a service call through `service.begin(ctx)`, `ctx.enrich` for notices, a per-tool `errors` contract, and the shared `formatInterpro` formatter.
|
|
52
52
|
|
|
53
53
|
```ts
|
|
54
54
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
@@ -96,7 +96,7 @@ export const interproGetEntry = tool('interpro_get_entry', {
|
|
|
96
96
|
});
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
There are no resources or prompts
|
|
99
|
+
There are no resources or prompts. The InterPro API is keyless; the one server-specific environment variable, optional `INTERPRO_SCAN_EMAIL` (parsed in `src/config/server-config.ts`), is the contact address the EBI Job Dispatcher requires for InterProScan submissions. Unset, `interpro_scan_sequence` still serves precalculated matches and fails other sequences as `scan_not_configured`; the hosted instance leaves it unset. The scan tools (`interpro_scan_sequence`, `interpro_get_scan_result`) run through `src/services/sequence-scan/`, outside the InterPro pacer, and `interpro_scan_sequence` is the only tool that is not read-only. `interpro_get_structure_domains` lifts each match's nested chain records into top-level `structures[]` joined by `entry` to stay inside the depth-8 parity walker, and its numbering contract (chain `start`/`end` beside author `auth_start`/`auth_end`, UniProt positions) is retained verbatim. Optional `proteomeId` on discovery joins the route after `taxonId` and binds to the cursor scope only when present. Search/member pages clamp positive integer limits to 100, discovery to 50, with default 20 and composed notices. GO filters require the InterPro source and accept either `goTerm` or `goCategory`, never both; member recovery follows `member_databases` or `integratedInto`. Entry `sections` selects named metadata while retaining core and unknown fields; explicit `overlapLimit` enables whole-record paging. Retained descriptions gain readable `descriptionText` through `htmlparser2`, alongside unchanged raw descriptions and annotation flags. Protein maps append requested residue rules after matches and extra features, preserving complete records and old cursor scopes when the new flag is absent/false. Discovery requests native fragment status on every page; optional `architectureId` adds native IDA grouping and explicit entry/taxon detail availability without inventing missing arrays. Bind only explicit selections to cursor scope and preserve unknown upstream values.
|
|
100
100
|
|
|
101
101
|
### Server identity and instructions
|
|
102
102
|
|
|
@@ -106,9 +106,13 @@ There are no resources or prompts and no server-specific environment variables:
|
|
|
106
106
|
await createApp({
|
|
107
107
|
name: 'interpro-mcp-server',
|
|
108
108
|
title: 'interpro-mcp-server',
|
|
109
|
-
tools: [/*
|
|
109
|
+
tools: [/* nine definitions */],
|
|
110
110
|
sessionMode: 'stateless',
|
|
111
|
-
|
|
111
|
+
skills: 'skills',
|
|
112
|
+
setup() {
|
|
113
|
+
initInterproService();
|
|
114
|
+
initSequenceScanService(getServerConfig().scanEmail);
|
|
115
|
+
},
|
|
112
116
|
teardown() { disposeInterproService(); },
|
|
113
117
|
instructions: '…',
|
|
114
118
|
});
|
|
@@ -182,12 +186,15 @@ See framework CLAUDE.md and the `api-errors` skill for the full auto-classificat
|
|
|
182
186
|
```text
|
|
183
187
|
src/
|
|
184
188
|
index.ts # createApp() entry point
|
|
189
|
+
config/
|
|
190
|
+
server-config.ts # INTERPRO_SCAN_EMAIL parsing (lazy, validated at startup)
|
|
185
191
|
services/
|
|
186
192
|
interpro/
|
|
187
193
|
interpro-service.ts # Paced, cancellable request boundary (init/accessor pattern)
|
|
188
|
-
http-adapter.ts # node:https HTTP/1.1 transport with 204 handling
|
|
194
|
+
http-adapter.ts # node:https HTTP/1.1 transport with 204 handling; also carries the scan tools' Matches API and Job Dispatcher calls
|
|
189
195
|
routing.ts # Accession → database routing, fixed-origin URL building
|
|
190
196
|
schemas.ts # Wire and output Zod schemas
|
|
197
|
+
structure-schemas.ts # PDB ID and chain validation, structure and chain-record schemas
|
|
191
198
|
cursors.ts # Opaque cursor envelopes
|
|
192
199
|
budget.ts # 100,000-byte response budget and whole-item fitting
|
|
193
200
|
relationships.ts # Clan relationship-graph slicing
|
|
@@ -195,9 +202,14 @@ src/
|
|
|
195
202
|
format.ts # Shared content[] formatter
|
|
196
203
|
description-text.ts # Readable HTML fragment projection for entry detail
|
|
197
204
|
upstream-errors.ts # Shared upstream error contract rows
|
|
205
|
+
sequence-scan/
|
|
206
|
+
sequence.ts # Sequence parsing and the UniParc MD5 digest
|
|
207
|
+
scan-schemas.ts # Matches API, Job Dispatcher, and match-record schemas
|
|
208
|
+
sequence-scan-service.ts # Precalculated lookup, job submission and polling, in-flight cap
|
|
209
|
+
scan-output.ts # Shared scan output schema and match segmentation
|
|
198
210
|
mcp-server/
|
|
199
211
|
tools/definitions/
|
|
200
|
-
interpro-[name].tool.ts #
|
|
212
|
+
interpro-[name].tool.ts # Nine tool definitions
|
|
201
213
|
tests/
|
|
202
214
|
services/ # Service, adapter, and budget tests
|
|
203
215
|
tools/ # Tool contract tests
|
|
@@ -218,9 +230,18 @@ tests/
|
|
|
218
230
|
|
|
219
231
|
## Skills
|
|
220
232
|
|
|
221
|
-
|
|
233
|
+
Two skill trees live at the project root, written for different readers:
|
|
234
|
+
|
|
235
|
+
| Tree | For | Written by |
|
|
236
|
+
|:-----|:----|:-----------|
|
|
237
|
+
| `framework-skills/` | The agent developing this server — framework skills (`metadata.audience: external`) plus any development-time skills of the server's own | `init` and the `maintenance` sync (framework skills); you (your own) |
|
|
238
|
+
| `skills/` | The agents that install the server and call its tools — tool chains, identifier sources, gates | You, deliberately, with the `add-skill` skill. Absent by default; usually none is needed |
|
|
239
|
+
|
|
240
|
+
Development skills are modular instructions. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry. Their directory is deliberately not `skills/`: Claude Code and Codex auto-load a plugin's root `skills/`, so a server that ships `.claude-plugin/` or `.codex-plugin/` would hand them to every agent that installs it.
|
|
241
|
+
|
|
242
|
+
A published skill in root `skills/` reaches plugin installs and the `.mcpb` bundle as-is, ships in the npm package and the Docker image, and reaches MCP clients when the server opts in with `createApp({ skills: 'skills' })`. `lint:packaging` validates the tree. This server publishes one, `skills/interpro-guide/SKILL.md` (identifier chains, gates, and chain/author/UniProt numbering), served with `skills: 'skills'`.
|
|
222
243
|
|
|
223
|
-
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
244
|
+
**Agent skill directory:** Copy `framework-skills/` into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
224
245
|
|
|
225
246
|
Available skills:
|
|
226
247
|
|
|
@@ -232,6 +253,7 @@ Available skills:
|
|
|
232
253
|
| `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
|
|
233
254
|
| `add-resource` | Scaffold a new resource definition |
|
|
234
255
|
| `add-prompt` | Scaffold a new prompt definition |
|
|
256
|
+
| `add-skill` | Author a skill the server publishes in root `skills/` for the agents that use it — when one earns its place, structure, validation, delivery |
|
|
235
257
|
| `add-service` | Scaffold a new service integration |
|
|
236
258
|
| `add-test` | Scaffold test file for a tool, resource, or service |
|
|
237
259
|
| `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
|
|
@@ -279,7 +301,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
279
301
|
| `bun run audit:fix` | `bun audit fix` — upgrade vulnerable packages to the lowest safe version within existing ranges (`--dry-run` previews, `--latest` rewrites ranges). First response when `devcheck` flags a transitive advisory; then `bun update <name>`, then `bun dedupe` |
|
|
280
302
|
| `bun run audit:refresh` | Delete `bun.lock` and reinstall. Last resort after `audit:fix`, `bun update <name>`, and `bun dedupe` — re-resolves every ranged dep (the framework pin included) and rewrites the lockfile as `lockfileVersion: 2` |
|
|
281
303
|
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
282
|
-
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity (run by devcheck) |
|
|
304
|
+
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, `.mcpbignore` coverage, plugin manifests, the published `skills/` tree (run by devcheck) |
|
|
283
305
|
| `bun run list-skills` | Print the skill registry |
|
|
284
306
|
| `bun run tree` | Generate directory structure doc |
|
|
285
307
|
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
@@ -295,7 +317,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
295
317
|
| `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
296
318
|
| `bun run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
297
319
|
|
|
298
|
-
**Waived `devcheck` warnings.**
|
|
320
|
+
**Waived `devcheck` warnings.** The owner waived `format-parity-depth-limit` for the `…fragments[].start`, `…fragments[].end`, and `…fragments[].dc-status` output fields of `interpro_find_proteins_by_domain` and `interpro_get_protein_domains`, plus discovery's containing path `proteins[].entries[].entry_protein_locations[].fragments[]`. The architecture union moves discovery's three diagnostics to that array, so the current schema emits four warnings. These finite nested records exceed the framework's depth-8 parity walker; tests prove both surfaces retain them, pending [cyanheads/mcp-ts-core#531](https://github.com/cyanheads/mcp-ts-core/issues/531). Don't flatten or weaken the schema or add suppressions. Any warning outside these exact paths still blocks shipping.
|
|
299
321
|
|
|
300
322
|
**CI is one file.** `.github/workflows/codeql.yml` (scaffolded) is the only GitHub Actions workflow: CodeQL is GitHub-owned end to end, and the file runs only while the repo's CodeQL *default setup* is turned off. Verification — `devcheck`, tests, the release gates — runs locally; don't add a workflow that re-runs it.
|
|
301
323
|
|
|
@@ -303,7 +325,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
303
325
|
|
|
304
326
|
## Bundling
|
|
305
327
|
|
|
306
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips
|
|
328
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. `mcpb pack` reads `.mcpbignore`, not `.gitignore`, so every root path the bundle must not ship — source, tests, docs, caches, logs, agent docs, plugin manifests, gitignored local files — needs a root-anchored line there (`/docs/`, never `docs/`, which also strips `node_modules/*/docs/`); `lint:packaging` names each missing or unanchored line. Root `skills/` ships on purpose. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips four classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`framework-skills/`, `skills/`, `.claude/`, `.agents/`, `SKILL.md`); platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on; node-gyp build output beside a `binding.gyp` (`config.gypi`, Makefiles, `obj.target/`, `.deps/`, object files and debug symbols), which records the packing machine's paths — compiled `*.node` addons stay; and build-only package files — the framework's `changelog/`, `scripts/`, `templates/`, `CLAUDE.md`, `AGENTS.md`, and config bases (`biome.json`, `vitest.config.base.mjs`, `config/tsconfig.base.json`), and `better-sqlite3`'s `deps/` and `src/` C sources. A server using DataCanvas therefore ships a portable bundle without the DuckDB native — `@duckdb/node-api` is an optional peer loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
307
329
|
|
|
308
330
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match, that every `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.X}"` (the host substitutes nothing else — `"${X}"` reaches the server as that literal string), and that an optional string option carries `"default": ""`.
|
|
309
331
|
|
|
@@ -370,7 +392,10 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
370
392
|
- [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
|
|
371
393
|
- [ ] Registered in `createApp()` arrays (directly or via barrel exports)
|
|
372
394
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
395
|
+
- [ ] `plugin.json` + `mcp.json` (Agent Plugins 1.0.0 — read by Codex, Cursor, GitHub Copilot, VS Code, Kiro) populated — `plugin.json` `name` = the unscoped repo name (lowercase `a-z`, `0-9`, `-`, `.` only); `version`, `description`, `author`, `homepage`, `repository`, `license`, `keywords` from `package.json`; no other top-level field, `extensions` included. `mcp.json` holds one `"type": "stdio"` entry keyed by the unscoped name, `npx -y <full package name>`, and the same fixed `env` as `.codex-plugin/mcp.json`. Neither file carries a user-supplied variable (no `""`, no `${…}` besides `${PLUGIN_ROOT}`/`${PLUGIN_DATA}`): keys reach Codex through `.codex-plugin/mcp.json` `env_vars`, which works only while `.codex-plugin/plugin.json` keeps `"mcpServers": "./.codex-plugin/mcp.json"`
|
|
373
396
|
- [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = the unscoped repo name (never the npm scope — `lint:packaging` enforces this); `interface.shortDescription` from `package.json` description
|
|
374
397
|
- [ ] `.codex-plugin/mcp.json` updated — server name key is the unscoped repo name; every user-supplied variable (API key, contact email, instance URL) is listed in `env_vars` so Codex forwards it from the user's environment. Never write `"KEY": ""` into `env` — an empty value replaces the user's exported key and is read as unset
|
|
375
398
|
- [ ] `.claude-plugin/plugin.json` populated — `name`, `version`, `description`, `author`, `repository`, `license`, `keywords` from `package.json`; inline `mcpServers` entry keyed by the unscoped repo name. Every user-supplied variable is declared under `userConfig` (`type`, `title`, `description`; `sensitive: true` for keys and tokens; `required: true` or `default: ""`) and referenced from `env` as `"KEY": "${user_config.<option>}"` — mirror the `user_config` block in `manifest.json`. Never write `"KEY": ""` into `env`
|
|
399
|
+
- [ ] Any new root dev path has a root-anchored line in `.mcpbignore`; `bun run bundle` and `lint:packaging` pass
|
|
400
|
+
- [ ] If the server publishes a skill in root `skills/`: `lint:packaging` passes, and `field-test` verified every gate and identifier claim in it against live tool behavior
|
|
376
401
|
- [ ] `npm run devcheck` passes
|
package/Dockerfile
CHANGED
|
@@ -29,6 +29,11 @@ RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
|
29
29
|
# Copy the rest of the source code
|
|
30
30
|
COPY . .
|
|
31
31
|
|
|
32
|
+
# The skills a server publishes (`createApp({ skills: 'skills' })`) are read at
|
|
33
|
+
# runtime from the application root. Created when the project has none, so the
|
|
34
|
+
# production stage's copy below holds with or without one.
|
|
35
|
+
RUN mkdir -p skills
|
|
36
|
+
|
|
32
37
|
# Build the application
|
|
33
38
|
RUN bun run build
|
|
34
39
|
|
|
@@ -124,7 +129,7 @@ ENV NODE_ENV=production
|
|
|
124
129
|
# OCI image metadata (https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
|
125
130
|
ARG APP_VERSION
|
|
126
131
|
LABEL org.opencontainers.image.title="interpro-mcp-server"
|
|
127
|
-
LABEL org.opencontainers.image.description="Search InterPro entries, map
|
|
132
|
+
LABEL org.opencontainers.image.description="Search InterPro entries, map domains and functional sites onto UniProt proteins and PDB structures, find proteins by domain, and scan raw protein sequences via MCP. STDIO or Streamable HTTP."
|
|
128
133
|
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
129
134
|
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
|
130
135
|
LABEL org.opencontainers.image.source="https://github.com/cyanheads/interpro-mcp-server"
|
|
@@ -136,6 +141,7 @@ COPY --from=deps /usr/src/app/node_modules ./node_modules
|
|
|
136
141
|
|
|
137
142
|
# Copy the compiled application code from the build stage
|
|
138
143
|
COPY --from=build /usr/src/app/dist ./dist
|
|
144
|
+
COPY --from=build /usr/src/app/skills ./skills
|
|
139
145
|
|
|
140
146
|
# Mirror CLI (MirrorService adopters only — Tier 3, opt-in):
|
|
141
147
|
# Copy your mirror lifecycle scripts and emit a runtime tsconfig so Bun resolves
|
|
@@ -175,6 +181,8 @@ ENV MCP_TRANSPORT_TYPE="http"
|
|
|
175
181
|
ENV MCP_SESSION_MODE="stateless"
|
|
176
182
|
ENV MCP_LOG_LEVEL="info"
|
|
177
183
|
ENV LOGS_DIR="/var/log/interpro-mcp-server"
|
|
184
|
+
# Optional, no default: set INTERPRO_SCAN_EMAIL at run time (docker run -e) to let
|
|
185
|
+
# interpro_scan_sequence submit InterProScan jobs; unset, it serves precalculated matches only.
|
|
178
186
|
|
|
179
187
|
# Expose the port the server listens on
|
|
180
188
|
EXPOSE ${MCP_HTTP_PORT}
|