Conversation
) Adds support for MCP protocol version 2026-07-28 ([release candidate](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/)) by migrating the client stack to the TypeScript SDK v2 beta (`@modelcontextprotocol/client`). mcpc now probes each server with `server/discover` and talks the new stateless protocol when supported, falling back to 2025-11-25 automatically on the same connection. - Resource subscriptions and list-change notifications use `subscriptions/listen` streams on 2026-07-28 connections (opened only for capabilities the server declares, re-established with backoff on drops); legacy connections keep `resources/subscribe` and unsolicited notifications - `ping` maps to `server/discover` on 2026-07-28 servers; `logging-set-level` errors there (both were removed from the protocol) - Task commands are reimplemented on raw 2025-11-25 requests (the v2 SDK dropped the experimental tasks API); they report the tasks extension as not yet supported on 2026-07-28 servers - OAuth ported to the v2 auth API, including RFC 9207 `iss` validation of authorization callbacks - The `--proxy` MCP server and e2e test server stay on SDK v1 (still serving 2025-11-25) until the v2 server packages are adopted — planned follow-up E2E suite passes at parity with `main`. ## Follow-ups (separate PRs) - **E2E protocol-version matrix**: add a second test server built on `@modelcontextprotocol/server@beta` (mirroring the current server's surface, ideally with a v2-only/`legacy: reject` mode to prove pure 2026-07-28 operation), parameterize the e2e framework with a `--server-protocol` flag, and run the protocol-agnostic suites against both servers in CI plus era-specific suites for fallback (v1) and listen-stream behavior incl. re-listen and resource file-sync (v2). Each future MCP revision then adds a matrix column instead of a rewrite, guarding backward compatibility as versions accumulate. The current suite covers the legacy-fallback path only; the modern path was verified manually against a real v2 server ([review](#314 (comment))). - **Tasks extension**: stop advertising the v1-shaped `tasks: {list, cancel}` client capability on 2026-07-28 connections — capabilities are declared before version negotiation, so the clean fix is moving tasks to the negotiated `extensions` map once the SDK ships the `io.modelcontextprotocol/tasks` extension. - **v2 server packages**: migrate the `--proxy` MCP server (and the e2e servers above) off SDK v1. https://claude.ai/code/session_013kwM8qhutYS3ZmQATcaQ9C --------- Co-authored-by: Claude <noreply@anthropic.com>
Adds the protocol-version test matrix from PR #314's follow-ups: the e2e suites now also run against a second test server speaking pure MCP 2026-07-28 (legacy requests rejected), so both protocol eras are covered in CI. The matrix immediately caught a real interop bug — SDK beta.5 servers require the new `Mcp-Method` header, which the beta.4 client never sent, so mcpc silently fell back to the 2025 handshake and failed against modern-only servers — fixed by updating the MCP SDK v2 to `2.0.0-beta.5`. - New `test/e2e/server/index-v2.ts` on `@modelcontextprotocol/server` v2; both servers serve the same surface from shared `fixtures.ts` - `./test/e2e/run.sh --server-protocol legacy|modern` (default: legacy) + `require_server_protocol` for era-specific suites; new CI jobs run the modern column - Both columns fully green (47/47), incl. previously untested `subscriptions/listen` resource file-sync and re-sync paths - MCP SDK packages exempted from pnpm's `minimumReleaseAge` gate so mcpc can track the fast-moving v2 betas - Test-robustness fixes: proxy/CA env passthrough to npx-spawned stdio servers, `NO_PROXY` cleared in the env-proxy suite, wait-loops instead of fixed sleeps after bridge kills Refs #314 https://claude.ai/code/session_01JsCXKviUugepDQZu8myGMn --------- Co-authored-by: Claude <noreply@anthropic.com>
Adds MCP's [Enterprise-Managed Authorization](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization) extension (SEP-990): sign in once with corporate SSO at the enterprise IdP, and mcpc then obtains MCP server tokens via identity assertion grants (ID-JAG, RFC 8693 token exchange + RFC 7523 jwt-bearer) with no per-server consent screens. The SDK v2's `CrossAppAccessProvider` drives the exchanges; mcpc supplies the IdP SSO and grant plumbing, mirroring the existing client-credentials grant. - New `mcpc login <server> --grant id-jag --idp <issuer> --idp-client-id <id> [--idp-client-secret <s>] --client-id <id> --client-secret <s>`, with full-chain validation at login (fail fast) - ID token kept fresh via the IdP refresh token; rotated tokens persisted from the bridge on the sanctioned OAuth-refresh keychain path; dead SSO sessions land in `unauthorized` with a re-login hint - Material stored as one OS keychain blob per profile, delivered to the bridge via IPC (never argv); profile listing labels these profiles "enterprise" - Advertises the extension in client capabilities on id-jag connections only - 19 new unit tests (RFC 8693 wire format, refresh/rotation, error paths); smoke-tested end-to-end against a mock IdP + mock MCP authorization server Follow-ups deferred: public/CIMD clients at the MCP AS (SDK beta.5 requires `clientSecret`), SAML assertions, e2e mock-IdP suite. https://claude.ai/code/session_01KFAG6CNK4kftV6RvHe2Jqi Co-authored-by: Claude <noreply@anthropic.com>
Routine dependency refresh: bumps every devDependency with a newer release that clears the repo's 5-day `minimumReleaseAge` quarantine. The MCP TypeScript SDK v2 packages are already on `2.0.0-beta.5` — the newest published beta — so they're unchanged. No runtime dependencies touched, hence no changelog entry. - `@types/node` 25.9.4→26.1.1, `c8` 11→12, `vitest` + `@vitest/coverage-v8` 4.1.9→4.1.10 - `eslint` 10.6.0→10.7.0, `typescript-eslint` 8.62.1→8.65.0, `prettier` 3.9.4→3.9.6, `tsx` 4.23.0→4.23.1, `viem` 2.55.4 - TypeScript 7.0.2 held back: `tsc` builds clean on it, but typescript-eslint peers at `<6.1.0` and hard-errors at load (typescript-eslint#10940) - undici 8 held back: raises `engines.node` to >=22.19.0 (mcpc declares >=22.12.0) and enables HTTP/2 by default, which changes the proxied-fetch path in `src/lib/proxy.ts` - Verified locally: lint, build, 892 unit tests, e2e legacy (47/47) and modern protocol matrix Refs #16 https://claude.ai/code/session_017R8sV6TmRF68ZvkK24dTGm Co-authored-by: Claude <noreply@anthropic.com>
Adds `--mcp-version <version>` to `mcpc connect` (and an `mcpVersion`
field in mcp.json entries) to pin the MCP protocol version instead of
auto-negotiating. The pin is strict: the connection fails with an
actionable error unless the server agrees to exactly the requested
version.
- Modern pin (2026-07-28) maps to the SDK's `{ pin }` mode; legacy pins
run the plain `initialize` handshake offering only the pinned version
- Pin persists in sessions.json (survives `restart`) and shows as
`(pinned)` in `mcpc @session`
- Supported versions live in a dependency-free `src/core/protocol.ts`
(CLI startup never loads the SDK); a unit test guards drift against the
SDK's list
- New e2e suite runs in both eras of the protocol matrix;
docs/help/skill updated
Refs #314
https://claude.ai/code/session_01DCJziR1mQfJk9XynQCwsFx
Co-authored-by: Claude <noreply@anthropic.com>
Sessions resumed after a bridge crash lost their negotiated protocol version: session details showed `Protocol: unknown (stateful)` without the server name, and all requests on the resumed connection were sent without the required `MCP-Protocol-Version` header. The SDK skips the initialize handshake when reconnecting with a preserved `MCP-Session-Id`, so mcpc now seeds the reconstructed transport with the version persisted in sessions.json. - Thread the stored `protocolVersion` through the resume path (bridge manager → bridge → transport), using the SDK transport option intended for exactly this case - Derive the protocol era from the restored version so era-dependent routing keeps working on resumed connections - Fall back to persisted `serverInfo` in session details after resumption - New e2e test crashes the bridge and asserts the resumed session keeps its protocol version, server info, and session ID (verified to fail without the fix) - Also adds an e2e guard asserting stdio sessions report a real protocol version (the mcpc ≤ 0.5.0 symptom from modelcontextprotocol/typescript-sdk#1468) Fixes #324. Refs #325 (follow-up: capabilities/instructions after resumption). https://claude.ai/code/session_011pqNs7aoZWzXjgBUxAsias --------- Co-authored-by: Claude <noreply@anthropic.com>
The MCP spec and TypeScript SDK use `protocolVersion` as the canonical term, so this renames the `mcpc connect --mcp-version` flag to `--protocol-version` and the mcp.json config field `mcpVersion` to `protocolVersion`. No deprecation alias — the flag was added in unreleased #320, so nothing shipped under the old name. - Internal option fields, `protocol.ts` constants/helpers, docs (README, SKILL.md, CLAUDE.md), and the changelog entry renamed to match - E2E suite renamed to `protocol-version.test.sh`; the JSON pin now appears as `_mcpc.server.protocolVersion` Refs #320 https://claude.ai/code/session_01TpJ2kbEL9zSS4baM3CGU5E Co-authored-by: Claude <noreply@anthropic.com>
…328) Resuming a stateful HTTP session reuses the server-side session and so skips the `initialize` handshake, leaving the SDK client with no capabilities and no instructions. After a crash-recovery restart the session showed no capabilities, `grep` no longer found the server instructions, and `resources-subscribe` wrongly refused with "server does not support resource subscriptions". - Persist capabilities and instructions in `sessions.json` at the connect that performs the handshake, and restore them for the lifetime of a resumed bridge - Route every bridge-side read through one helper, so the subscribe pre-check, the tools-cache warmup and the `--proxy` server all see the restored values - Skip instructions larger than 32 KB, and keep them out of the `mcpc --json` session list (they can be kilobytes per session) - Extend the resume e2e test with capabilities, instructions and a `resources-subscribe` round trip (verified to fail without the fix) Fixes #325. Refs #324. https://claude.ai/code/session_01YRqAADGF3hWDQ83t4FvtHJ --------- Co-authored-by: Claude <noreply@anthropic.com>
A `protocolVersion` field in an mcp.json entry never reached the client, so `mcpc connect cfg.json:entry` auto-negotiated instead of pinning, with no error or warning — only the `--protocol-version` flag worked. `substituteEnvVars()` rebuilt each entry from a per-field allowlist and simply forgot the field. - The config copier now passes every field through and rewrites only those needing env-var substitution or URL normalization, so future `ServerConfig` fields can't be dropped the same way. - An unsupported pin from a config entry is now rejected up front with the same error as the flag, instead of failing later inside the bridge. - Unit tests for the preserved pin and unknown-field pass-through, plus e2e coverage in `basic/protocol-version.test.sh` (both protocol eras). No changelog entry: config-entry `protocolVersion` is still in `[Unreleased]` (#320), so the existing "Added" line already describes the working behaviour. Fixes #323 Refs #320 https://claude.ai/code/session_01D4Y47mxUVcz73X13R5f4sJ Co-authored-by: Claude <noreply@anthropic.com>
jancurn
pushed a commit
that referenced
this pull request
Jul 27, 2026
…-07-28 Extends the previous era-only gate: `--task`/`--detach` now also fail when the server does not advertise `tasks.requests.tools.call`, instead of warning and running the tool synchronously. The flags change the shape of the output, so the fallback left callers parsing a `taskId` that was never there, with exit code 0 — the output shape has to be predictable. - Add `tasksUnsupportedByServerMessage()` beside the era message, so the CLI gate and the bridge backstop report the same reason - Drop the "falling back to synchronous execution" warning path - Add a `NO_TASKS` flag to the legacy test server (capability withheld, task handlers unregistered) and cover both refusal reasons in the e2e suite, one per protocol era - Update the tools-call help text, README, skill and changelog Refs #316 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgotfZLGkL4CeYE6GGuq2F
…it tests (#329) Follow-up review fixes on top of #316. `tools-call --detach` silently fell through to a plain synchronous `tools/call` on 2026-07-28 connections, handing scripts a tool result with exit 0 where they parse a `taskId` — while the README, CHANGELOG and skill all promised an error. Also adds the unit-test file `mcp-client.ts` was missing. - Gate `--task`/`--detach` in `shouldUseTask` (the CLI decides before the bridge sees it), sharing one message with the `tasks/*` gate - Hoist `assertTasksAvailable()` out of the task try blocks, so the reason is no longer nested in `Failed to list tasks: …` with a doubled period - Add `test/unit/core/mcp-client.test.ts` (29 cases) for the era-dependent logic: `subscriptions/listen` open/rollback/re-listen, connection mode, resumed-session era fallback, stateless tools-cache expiry, per-era gates - Add a modern-only e2e suite guarding the task gates end to end - Merge the duplicated re-listen backoff loops; README: sampling is not deprecated by MCP (it gained `context`/`tools` in 2026-07-28) Refs #316 https://claude.ai/code/session_01DgotfZLGkL4CeYE6GGuq2F --------- Co-authored-by: Claude <noreply@anthropic.com>
#329 made `tools-call --task` fail with a server error when the server doesn't advertise `tasks.requests.tools.call`, instead of warning and falling back to a synchronous call. The conformance adapter still ran that command expecting exit 0, so the `conformance / tools_call` job failed and gated the release ([run](https://github.com/apify/mcpc/actions/runs/30302773413/job/90099506437)) — the scenario's own server-side checks passed 2/2, only the adapter's exit code failed it. Test-harness only, no behaviour change. - `runMcpc()` takes an `expectExitCode` option (default `0`) - The `tools_call` scenario now asserts the `--task` call exits with code 2, so the gate stays guarded instead of being swallowed - Refreshed the stale comment that still described the old fallback Refs #329 https://claude.ai/code/session_01AxYXW15gWXNWFPpSGqQTLV Co-authored-by: Claude <noreply@anthropic.com>
…333) Wiring up the two SEP-1046 client-credentials conformance scenarios found a real bug: `login --grant client-credentials` looked for the authorization server only on the MCP server's own origin, never fetching the RFC 9728 protected resource metadata document. An authorization server on a different origin — what the spec prescribes — was unreachable without passing `--token-endpoint` by hand. Discovery now tries protected resource metadata first and follows `authorization_servers`, falling back to the previous probes. The default conformance matrix goes from 2 scenarios / 3 checks to 4 scenarios / 31 checks. - Add `auth/client-credentials-{basic,jwt}` to the adapter and the CI matrix - Discover via protected resource metadata, incl. RFC 8414 issuer-path handling; only the client-credentials path opts in, the id-jag callers pass issuer URLs directly and are unchanged - Cover the new discovery path with unit tests - Document current coverage and the remaining gaps in `test/conformance/README.md` - Add a CLAUDE.md rule to keep conformance tests updated like the e2e tests The scenarios still missing all drive the browser-based authorization-code grant and need adapter scaffolding first; tracked in #332. Refs #332, #329 https://claude.ai/code/session_01AxYXW15gWXNWFPpSGqQTLV Co-authored-by: Claude <noreply@anthropic.com>
Upgrades the MCP TypeScript SDK v2 packages (`@modelcontextprotocol/client`, `core`, `server`, `node`) from `2.0.0-beta.5` to the stable `2.0.0` release. No code changes were needed — the breaking changes since the betas (`serverInfo` moved to response `_meta`, JSON-serialized response cache) are handled inside the SDK. Verified: unit tests (944/944), both e2e protocol matrices (legacy 2025-11-25 + modern 2026-07-28, 50/50 each), and all covered conformance scenarios pass. https://claude.ai/code/session_01HGa9mKfxSh5G1DmELuhaBA Co-authored-by: Claude <noreply@anthropic.com>
Help text was wrapping onto two or three lines in the command lists (`logging-set-level` took three), and `mcpc @session --help` never documented its `--json` output. Session details also said `Protocol: 2025-11-25 (stateful)` — without saying which protocol, and with the mode attached to the version rather than to the transport it actually describes. - Every command/option description now fits on one line; details moved into titled `addHelpText` sections (`logging-set-level`, `ping`, `connect --protocol-version/--x402`, 8 `login` options, `x402`) - `mcpc @session`, `restart` and `close` now document their `--json` shape like every other command - Session details now read `MCP version: 2025-11-25 / Streamable HTTP (stateless)` (or `/ stdio (stateful)`), naming the protocol and the transport; new `_mcpc.transport` field in `--json` - `mcpc @session` no longer offers `logging-set-level` / `tasks-*` on 2026-07-28 connections, where they only error out, and flags those capabilities as era-limited - e2e runner reported era-skipped suites as passed, so a missing matrix column looked green: suites skip via `skip_suite` and `run.sh` prints `⊘` plus a `Skipped: N` line New guards in `test/e2e/suites/basic/help.test.sh` walk the whole help surface for wrapped descriptions and missing JSON sections; CLAUDE.md records the rules. No originating issue — requested in the session below. https://claude.ai/code/session_011nvJzr76VzjJFyG9eGZfB5 --------- Co-authored-by: Claude <noreply@anthropic.com>
Merges `main` into `draft` so the draft branch (SDK v2 migration) can later merge back into `main` without conflicts. The conflicts all came from the dependency update on main (#338) colliding with the SDK v2 migration on draft. - package.json: keep the SDK v2 packages, take main's bumps of `@modelcontextprotocol/sdk` (^1.30.0) and `viem` (^2.55.8) - pnpm-workspace.yaml: union of both `minimumReleaseAgeExclude` lists - CHANGELOG.md: keep draft's entries, fold in main's dependency-update line - pnpm-lock.yaml: regenerated from the merged package.json Refs #338 https://claude.ai/code/session_01MtRQZh2W13VFvpmrJfFwWQ Co-authored-by: Claude <noreply@anthropic.com>
Member
Author
|
@copilot resolve the merge conflicts in this pull request |
Contributor
Resolved the merge conflicts in 972fa39. The conflicts were in
|
…340) Two wording fixes on the session details screens. `MCP version:` looked like it also titled the transport after the slash, and the `JSON output (--json):` block under `mcpc @session --help` read as if it applied to all the subcommands listed above it. - `MCP version: 2025-11-25 / Streamable HTTP (stateful)` → `MCP: version 2025-11-25 / Streamable HTTP (stateful)` - session details `--json` help is now one inline sentence with the shape, dropping the extra `_mcpc` field breakdown - `connect`, `restart` and `mcpc @session` now share one wording and one shape example (`connect` wraps it in an array, which is what it returns) Refs #336 https://claude.ai/code/session_01BdeG5Pz7tSKWbTd7uG6Dx4 --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…r debug check (#347) Fixes two OAuth-related log annoyances, one of which was masking a real security check. `mcpc login` printed an SDK warning that the provider does not implement `saveDiscoveryState()`/`discoveryState()`, leaving the SEP-2352 callback-leg authorization-server binding unchecked; the provider now records the discovered authorization server in memory (same durability as the PKCE code verifier — both login legs share one provider instance in one process), so the SDK verifies the authorization code is redeemed at the server that minted it. - Implement `saveDiscoveryState()`/`discoveryState()` on `OAuthProvider` (+ unit tests) - Remove a stale debug block in `createStreamableHttpTransport()` that logged a spurious `authProvider.tokens() is NOT a function - this is a bug!` error on every OAuth connection (SDK v2 wraps the provider in an adapter exposing `token()`, so the check asserted an obsolete shape) https://claude.ai/code/session_01Cy2yB65N7awpCvjMyLjJC1 Co-authored-by: Claude <noreply@anthropic.com>
…348) Connecting to a server without 2026-07-28 support dumped a scary `Transport error: SdkHttpError ... Bad Request: No valid session ID provided` stack trace into the bridge log on every connect. That HTTP 400 is the expected way such servers decline the `server/discover` version probe — the SDK falls back to the legacy `initialize` handshake and the connection succeeds — so it is now logged as a single debug line instead. - Recognize the expected probe rejection (pre-connect, auto negotiation, non-auth 4xx) in the transport error handler - Keep full error logging for 401/403, 5xx, pinned `--protocol-version` connections, and post-connect errors - Unit tests for the classifier and all three logging paths; verified end-to-end against the legacy e2e server Refs #347 (removed a different spurious log message; this one remained). https://claude.ai/code/session_01DceGk44vcV9jfyAHYKpp4h Co-authored-by: Claude <noreply@anthropic.com>
Updates all version-pinned MCP spec links (schema, authorization, security best practices, lifecycle) from `2025-11-25` to `2026-07-28`, so docs and `--help` output point at the latest live spec. Three anchors don't exist on the 2026-07-28 schema page and stay on `2025-11-25` on purpose, via a new `LEGACY_SCHEMA_BASE` constant: - `InitializeResult` — the stateless era replaced the `initialize` handshake with `server/discover`'s `DiscoverResult` - `CreateTaskResult`/`Task` — tasks moved out to the `io.modelcontextprotocol/tasks` extension, not yet implemented by the SDK; added a TODO to revisit these links once that support lands The README sessions section keeps its `2025-11-25` lifecycle link too, but that one's deliberate as a historical reference to the stateful protocol era, not a miss. Also fixed two related doc gaps found while cross-checking the schemas: - `resources-list`/`resources-templates-list` `--help` showed `name?` (optional) even though `name` is required per `BaseMetadata` in both spec versions - `resources-read`/`skills-get` `--help` didn't mention `ttlMs`/`cacheScope`, new caching-hint fields `ReadResourceResult` gained in 2026-07-28 All links (updated and kept-as-is) verified live against both spec pages. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01XYydaLm3b4Lger6sdkv7vE --------- Co-authored-by: Claude <noreply@anthropic.com>
`mcpc connect` / `mcpc @session` / `restart` returned an `InitializeResult`-shaped object, so on 2026-07-28 connections everything `server/discover` carries beyond the legacy handshake was dropped, and none of it reached `sessions.json`. `ServerDetails` now reconciles both results — the fields they share, plus the discover-only `supportedVersions` and `_meta` (absent on legacy connections; never synthesized there). - `--json` and `sessions.json` gained `supportedVersions` and `_meta`; both are restored for resumed sessions, which skip the handshake - `SessionData.serverInfo` is typed as the full `Implementation` it already stored - Fixes the server identity on modern connections: 2026-07-28 moved `serverInfo` into a per-response `_meta` key, and the SDK only lifts it at connect while `ping` refreshes the discover result — so after a mid-session redeploy, details reported a stale `serverInfo` beside a fresh `_meta`. Both now come from the same snapshot - Tools cache honors a server-sent `ttlMs` hint (SEP-2549), and explicit refreshes (`tools-list`, `list_changed`) pass `cacheMode: 'refresh'` so the SDK's response cache cannot answer them with a stale list. `cacheScope` needs no handling: one bridge serves one session, i.e. one authorization context - Reformatted the help for these commands: titled `Output:` / `JSON output (--json):` sections instead of trailing prose, one schema link per line, and the protocol eras named once Refs #345 https://claude.ai/code/session_01RZJucu49mLZKJvUYiaY3UV --------- Co-authored-by: Claude <noreply@anthropic.com>
…351) The Windows/Bun leg of the last release run failed on `sessions/logs` test 10 with `Session not found: @fold-...`. Suites that inject synthetic session entries did an unlocked `jq ... > tmp && mv` on `sessions.json` while a live bridge rewrote the same file on every keepalive ping — when the bridge loaded the file before the `mv` and saved after it, the injected entry vanished. Test-only flake, no product bug. - Add an `edit_sessions_json` framework helper that takes the same `proper-lockfile` lock mcpc uses (the `<file>.lock` directory, created with `mkdir`) - Break the lock once after 10s, matching proper-lockfile's staleness rule, so a SIGKILLed bridge's leaked lock can't hang a suite - Route the five unlocked fixture edits through it: three in `sessions/logs`, one each in `unauthorized-auto-detect` and `unauthorized-persist` Verified against a keepalive-style concurrent writer: the old pattern lost 2 of 60 injected entries, the helper lost 0 of 60. Full `sessions/` suite (18 tests) passes. Refs https://github.com/apify/mcpc/actions/runs/30614984280 https://claude.ai/code/session_01LV8fLqLtF7s3VMqiL73qfv Co-authored-by: Claude <noreply@anthropic.com>
jancurn
pushed a commit
that referenced
this pull request
Jul 31, 2026
main's tip (#316) is a squash-merge of the MCP 2026-07-28 work this branch already carried as individual commits, so the merge brings no functional change: the only difference between the two sides is this branch's dependency-age gate. Two resolutions were needed. CHANGELOG.md conflicted where this branch adds its `### Security` entry, kept as-is. pnpm-workspace.yaml auto-merged wrongly: the squash re-added the unresolved `allowBuilds:` / `esbuild: set this to true or false` placeholder that this branch deletes, and since the deletion is not a competing change to that region from the merge base, git silently took main's addition back. Removed again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7DpKbdofBXpGHfhi4TMMf
jancurn
added a commit
that referenced
this pull request
Jul 31, 2026
MCP 2026-07-28 removed `ping`, so `mcpc @session ping` silently probes with `server/discover` instead — invisible until it shows up in a server's access log, with no way to see what that request returns. This adds a command that says what it does. - `mcpc @session server-discover` sends `server/discover` and reports the answer: supported protocol versions (negotiated one marked), capabilities, instructions, `_meta`. `--json` prints the `DiscoverResult` verbatim. - On 2025-era connections it refuses (exit 2) and points at `mcpc @session`, whose `initialize` result carries the same data. - `ping` output now names the request it measured; `ping --json` is unchanged. - Capability rendering extracted so both screens share it; `SERVER_INFO_META_KEY` mirrored in the dependency-free `protocol.ts` with an SDK drift test. - New `basic/server-discover.test.sh` e2e suite (one branch per protocol era); README, CHANGELOG and the agent skill updated. Refs #316 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01KHDUfie1HZtvSiqFNTYs17 --- _Generated by [Claude Code](https://claude.ai/code/session_01KHDUfie1HZtvSiqFNTYs17)_ Co-authored-by: Claude <noreply@anthropic.com>
jancurn
pushed a commit
that referenced
this pull request
Aug 2, 2026
A config entry's `env` routinely holds API tokens — directly or via `${VAR}`
substitution — but only `headers` were protected. Resolved `env` values were
written to `sessions.json` in plaintext, printed verbatim by `mcpc --json
@session` / `connect --json`, and passed to the bridge in its command line,
where `ps` exposed them.
They now follow the exact same path as headers: stored in the OS keychain
(`session:<name>:env`), redacted to `<redacted>` in `sessions.json` and all
`--json` output, and delivered to the bridge over IPC after spawn. The bridge
merges them back into the stdio transport config, so servers still get their
environment unchanged. Sessions written before this change keep working —
their on-disk plaintext is used as is; recreate a session to move its values
into the keychain.
Rebuilt on main after the draft branch was squashed in as #316.
Fixes #341
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rmdd458q2Bx68bPxuUtQGa
jancurn
pushed a commit
that referenced
this pull request
Aug 6, 2026
A config entry's `env` routinely holds API tokens — directly or via `${VAR}`
substitution — but only `headers` were protected. Resolved `env` values were
written to `sessions.json` in plaintext, printed verbatim by `mcpc --json
@session` / `connect --json`, and passed to the bridge in its command line,
where `ps` exposed them.
They now follow the exact same path as headers: stored in the OS keychain
(`session:<name>:env`), redacted to `<redacted>` in `sessions.json` and all
`--json` output, and delivered to the bridge over IPC after spawn. The bridge
merges them back into the stdio transport config, so servers still get their
environment unchanged. Sessions written before this change keep working —
their on-disk plaintext is used as is; recreate a session to move its values
into the keychain.
Rebuilt on main after the draft branch was squashed in as #316.
Fixes #341
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rmdd458q2Bx68bPxuUtQGa
jancurn
added a commit
that referenced
this pull request
Sep 15, 2026
mcpc's skills support tracked the pre-July-2026 SEP-2640 draft (a `skill://index.json` discovery file with `skill-md`/`archive`/`mcp-resource-template` entry types), none of which survived into the extension as it landed. This implements the [stable spec](https://github.com/modelcontextprotocol/ext-skills): `skills/list`, `skills/get`, and the optional `resources/directory/read`, on MCP 2026-07-28+ servers that declare the extension. No backwards compatibility with the draft. - `skills-list` prints spec-shaped entries (frontmatter + complete file manifest) in `--json` - `skills-get <skill> [file]` reads a SKILL.md or a supporting file and verifies it against the manifest (size, digest, frontmatter) — content failing a check is refused, not printed - New `resources-directory-read <uri>`, gated on `"directoryRead": true` - Adds a dependency-free SKILL.md frontmatter parser and result validators (the SDK ships no schemas for these methods) - E2E: the 2026-07-28 test server now serves all three methods and can be made to contradict its own manifest; a new legacy suite pins the refusal on 2025-11-25 Refs https://github.com/modelcontextprotocol/ext-skills, supersedes the draft implementation from #316 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Cf7cxfnnBxmDAsDbV4tfEf Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks the following PRs:
#314
#315
#318
#319
#320
#326
#327
#328
#329
#330
#331
#337
#336
#339
#340
#345
#347
#348
#349
#351