Soklet Logo

Model Context Protocol

MCP Compatibility and Scope

Soklet's 4.0 server target is MCP 2026-07-28. The current source also has an explicitly selected 2025-06-18 and 2025-11-25 compatibility path for synchronous tools, ordinary prompts, exact or templated resources, argument completion, request-scoped POST progress, framework static catalog pagination, and explicitly enabled sessions with remembered public client metadata, active-request cancelation, leased GET, verified DELETE, session-owned URI grants, and resource/catalog invalidations. This page describes each path's behavior, limitations, and the responsibilities of your application.

2026-07-28 transport contract

  • The MCP listener and port are separate from ordinary Soklet HTTP and SSE servers.
  • Endpoints use exact non-root paths and compile-time descriptors or immutable programmatic registrations.
  • Discovery uses server/discover directly; no initialization handshake or session is required.
  • Messages use POST; OPTIONS is reserved for CORS preflight, and GET/DELETE return 405.
  • Requests use Content-Type: application/json and Accept must permit both JSON and SSE according to protocol negotiation.
  • Every JSON-RPC request carries Mcp-Method. Tool calls, prompt gets, resource reads, and task operations also carry Mcp-Name; for tasks/get, tasks/update, and tasks/cancel, its value is the task ID. Headers must agree with the JSON-RPC payload.
  • Every request restates its MCP protocol version and client capabilities; there is no connection or session memory.
  • Notifications are exempt from name/method header requirements and never receive a JSON-RPC response body.
  • Independent concurrent requests may reuse an equal string or integer JSON-RPC ID. Soklet correlates within each request/stream and does not invent a listener-global sender namespace.
  • Server-to-client elicitation operations are nested only in correlated input_required results. Soklet never emits a server-originated top-level JSON-RPC request on an HTTP response or request-scoped SSE stream.
  • MCP HTTP responses use Cache-Control: no-store, regardless of protocol-level resource cache hints.

Last-Event-ID and MCP-Session-Id are ignored, never stored, and never echoed. They are also forbidden in application-authored MCP response headers, so attempts to emit either name fail closed. notifications/cancelled is accepted as an empty 202 after validation/admission/request limiting but intentionally does not cancel work.

Valid unknown entries in clientCapabilities.extensions remain opaque input available to admission. They do not invent a core capability, advertise matching server support, or get reflected into discovery. Malformed extension containers, identifiers, or settings fail with HTTP 400 / JSON-RPC -32602 before admission or downstream work.

2025-06-18 and 2025-11-25 compatibility

An endpoint and each callable operation must name at least one exact McpProtocolVersion. There is no implicit latest version. An endpoint can select both 2025 revisions and 2026-07-28 at the same URL, while individual tools, prompts, and resources can select subsets. The selected revision controls their listing and invocation. See Endpoint Authoring for annotation and programmatic configuration.

A client using either selected 2025 revision starts with initialize, may send notifications/initialized, and can call ping. Subsequent versioned POST requests support synchronous tools/list and tools/call, prompts/list and prompts/get, and resources/list, resources/templates/list, and resources/read. Prompt arguments and text, blob, and template resource reads use the same application handlers with revision-specific wire output. Sessions are disabled by default: that view does not issue a session ID or retain initialization metadata. To enable sessions, select exact 2025 revisions through the endpoint's sessionProtocolVersions and configure the server's required McpSessionConfig. Every later POST is freshly admitted and request-limited, then verifies owner, endpoint, revision, and lifecycle generation before exposing the remembered public client information/capabilities. Unknown, expired, wrong-owner, and wrong-path IDs share neutral 404 handling. See 2025 session configuration. An optional HTTP transport admission controller enables verified DELETE and, with selected legacy subscriptions and effective sources, leased GET opening. See HTTP transport admission configuration.

completion/complete uses the same prompt-argument and literal resource-template callbacks through either 2025 revision. Target membership, completer availability, prompt visibility, and the advertised completions capability follow the selected revision. On a Completion-enabled endpoint/revision, a visible registered target with a declared argument but no enabled completer returns empty suggestions; unknown or caller-hidden prompts and unknown template references return neutral invalid-parameters errors. A selected view with no enabled completer returns method-not-found. The server-wide request limiter is required for configured completers. See Argument completion for exact declarations and framing. Completion interoperability with particular clients and hosts remains unverified.

Request-scoped progress uses the existing reporter and a valid progress token through either 2025 revision. The first update commits the originating POST response to SSE; no update returns JSON. A committed legacy SSE disconnect or lost-writer write failure detaches delivery without itself canceling the handler, while deadlines and physical worker reservations remain in force. Finite/uncommitted or queued legacy requests and modern requests retain disconnect cancellation. Streams are persistent and nonresumable: Soklet intentionally omits November's recommended empty priming event and event IDs, and supplies no polling, replay/history, or lost-POST-result recovery. Progress display and the effect of omitted priming events remain unverified in particular clients and hosts. See Legacy POST progress.

Framework tools/list, prompts/list, static resources/list, and resources/templates/list support bounded pages on both 2025 revisions. A catalog that fits the existing response and localization limits remains one page. Each continuation uses fresh admission, request limiting, and applicable current catalog permissions. Framework cursors have a separate 2,048-byte ceiling and grant no permission; changed catalogs or negotiated locales and other invalid/hidden-anchor classifications return neutral JSON-RPC -32602. Custom resource-list handlers keep application-owned cursors, and modern static catalogs remain unpaged. See Static catalog pages on 2025 revisions for the complete navigation and snapshot contract. Pagination behavior in particular hosts remains unverified.

The adapter does not expose Skills, Apps UI, Tasks, subscriptions/listen, multi-round input, or server-initiated requests through either 2025 revision. On explicitly session-enabled 2025 views, admitted notifications/cancelled can target active client work if cancelation wins the terminal reservation; modern and session-disabled views keep the compatibility no-op. Automatic host recovery after session expiry and the suitability of session defaults for production remain unverified. Leased GET, verified DELETE, independently authorized URI grants, and resource/catalog invalidations are implemented. GET admission grants no URI permission; legacy delivery remains best effort with no event history or POST result recovery. The client notes below describe version-specific behavior; GET/DELETE recovery, authorization renewal, and reconciliation require testing with the client and authentication route you deploy. Generated Skill manifests and files remain exclusive to the modern view, including when both eras share a URL. 2025-03-26 is not supported by this adapter.

Accepted JSON-RPC operation results and errors use HTTP 200 on both 2025 revisions, with sessions enabled or disabled. Invalid operation arguments, an unknown resource, an invalid catalog cursor, or a handler failure remain per-call RPC outcomes. Authentication/admission rejection, rate/capacity limits, malformed HTTP or JSON-RPC envelopes, unsupported protocol selection, and invalid/unknown sessions retain their HTTP failure status. Once progress commits POST SSE, its terminal RPC result or error arrives in that stream.

Initialization negotiates from params.protocolVersion and returns that version unchanged when the endpoint supports it. Otherwise, a supported static 2025 MCP-Protocol-Version header can guide the counteroffer; without one, Soklet offers its newest configured 2025 revision. A June-only endpoint can therefore accept a November proposal with a June header and reply with June. A present invalid or unsupported header still receives HTTP 400.

An unsupported modern probe at a legacy-only endpoint receives an ordinary empty HTTP 400, allowing clients with 2025 fallback to try initialize at that URL. Other unsupported selectors retain a nonempty configured-revision diagnostic. This does not reinterpret initialization as modern framing or enable an undeclared revision.

Later legacy-shaped requests may omit the version header only on an endpoint serving exactly one supported 2025 revision. That explicit configuration identifies the POST, notification, and configured GET/DELETE revision. Modern and multi-version endpoints still require the header, even with a session ID: Soklet does not inspect an unauthenticated session to select an admission view. Clients should send the negotiated version on later requests. March is unsupported; interoperability still depends on the selected host and version.

Client behavior and tested limits

TypeScript Client/Core 2.2.0 supports session IDs, automatic GET opening and reconnection, resource subscribe/update/unsubscribe, and catalog invalidations on both supported 2025 revisions. Authorization renewal does not repeat a previously delivered resource hint. DELETE ends the session and its GET stream. These notes cover this SDK version and the listed features.

Automatic reconnection is bounded and version-specific. Additional review of TypeScript Client 2.3.1 and SDK 1.30.0 found that an initial notification-stream GET receiving 503 is reported as an error without an automatic retry; their default stream reconnection policy allows only two retries, with configurable options. Do not assume a successful connect() means the optional GET stream opened, or that a client will retry throughout an outage. Handle transport errors, apply bounded backoff, and explicitly recreate/reconnect the client when needed. Test initial admission failure and exhausted retries with the versions and options you deploy.

GET credential refresh does not refresh a URI grant's historical credentials; use a fresh or duplicate subscribe to replace URI credentials. Your URI authorizer must check current authority during renewal; an explicit denial retires the session and closes its GET streams. A reconnect receives 401 with an invalid_token challenge only if your HTTP transport admission controller returns that rejection for the revoked credential. DELETE also requires application admission, a still-active session, and an admitted credential resolving to the same owner to return 204. Soklet does not detect token revocation or issue OAuth tokens. OAuth token issuance and host-specific credential recovery remain application/deployment responsibilities and have not been verified by these SDK compatibility notes.

The following client versions have known behavior with session-enabled endpoints and legacy subscriptions. Other versions and features may differ.

ClientSelected revisionObserved behavior
MCP Inspector 2.9.0, web client in Chrome 154.0.8037.972025-06-18Tool, prompt, and resource catalogs refreshed automatically. Subscribe/unsubscribe and resource update markers are available. The resource preview required its Refresh button to reread contents. A dropped GET reconnected automatically with the existing session.
Visual Studio Code 1.139.12025-11-25The tool picker and prompt suggestions displayed changed names. The resource editor automatically reread and displayed updates whose byte length changed. A dropped GET reconnected automatically and delivered a fresh hint for a change during the gap; stopping the server sent DELETE.

For the tested VS Code version, specify the November header explicitly in the documented HTTP server configuration. Use a URL whose configured Soklet endpoint selects 2025-11-25:

{
  "servers": {
    "catalog": {
      "type": "http",
      "url": "https://api.example.com/mcp/2025-11-25",
      "headers": {
        "MCP-Protocol-Version": "2025-11-25"
      }
    }
  }
}

VS Code 1.139.1 did not automatically send the negotiated version header. Its configuration could not express a June version header that changed after November-to-June initialization negotiation, so June support remains unverified in that host. VS Code also cached resource reads for three seconds and used an editor ETag based on a fixed modification time and byte size; an immediate update or a same-size content change could leave the displayed text stale. Reopening its resource picker relisted the catalog. After a reconnect attempt received 503, the host stopped retrying; restarting the connection was necessary. These limitations apply to VS Code 1.139.1.

The SDK does not automatically reinitialize after a neutral session 404; applications need an explicit recovery policy. It also leaves a canceled tool-call promise pending after sending the cancellation notification alone, so callers need a bounded local wait. Recreate the client when recovering the connection. Catalog and URI hints remain best effort: reconnecting GET can deliver an unwritten pending invalidation, but does not repeat a notification fully written to another stream, replay events, or recover a lost POST result. Host-specific pagination and full OAuth recovery remain unverified.

This configuration applies to legacy body framing. Do not combine it with modern Mcp-Method or Mcp-Param-* mirrors. On a legacy call Soklet rejects any Mcp-Param-* header, and any Mcp-Method or Mcp-Name mirror that disagrees with the body, with -32020. Mirrors that agree with the body are accepted, but a legacy client should not send them. Headerless subsequent legacy calls are inferred only on an endpoint serving exactly one overall revision; a session ID alone does not select a revision.

On the modern profile, admitted application-execution failures/output contract errors and active application-handler deadlines return HTTP 200 with the correlated JSON-RPC -32603 error, preserving in-band client error handling. Intentional McpJsonRpcException and successful isError=true tool results keep separate mappings. Framework discovery/catalog policy, protocol deadlines, executor submission, capacity/rate and parser/transport failures keep their HTTP failure statuses; queued deadlines remain 503. Already committed SSE keeps its terminal result/error in the stream.

2026-07-28 validation and rejection precedence

The JSON-RPC request path has 17 ordered groups; the first failure wins:

  1. connection, header-count, header-size, request-size, and timeout limits;
  2. endpoint routing;
  3. Host authority, then Origin prevalidation and CORS authorization;
  4. POST-only method, Content-Type/Accept negotiation, and supported request content encoding (unsupported codings receive HTTP 415);
  5. strict JSON parsing;
  6. JSON-RPC envelope validation;
  7. required mirrored-header form and method agreement, plus name agreement except for caller-aware tools/call, and registration-independent custom-header policy for non-tool methods;
  8. exact selector membership and profile selection;
  9. selected-profile required _meta, key, extension/settings and universal-spine validation, then header/body version agreement;
  10. cheap method/structural validation;
  11. application admission, then caller-neutral target/descriptor lookup, custom tool mirrored headers, deferred caller-aware Mcp-Name agreement, request-state shape and required capabilities, followed by the optional request limiter and resolved tool limiter;
  12. bounded queue admission and handler-slot acquisition;
  13. the application handler interceptor;
  14. complete application input conversion and validation, including Profile 1 tool input-schema evaluation;
  15. handler invocation;
  16. preliminary result-shape recognition, applicable tool-output sanitization, then remaining result/output-schema validation; and
  17. envelope generation and response write.

Caller-aware tool/prompt catalogs retain their access-policy and quota ordering after admission. An unsupported tool-call selector fails at profile selection without consulting registered custom headers; protocol/method/header-shape checks still fail earlier. Caller-aware tools/call defers Mcp-Name agreement until after admission, catalog access policy and the tool rate limiter.

Notifications have a separate shorter order. Their common prefix is limits, routing, Host, Origin/CORS, POST/media/Accept/content encoding, strict JSON, and envelope classification. A classified notification first validates selector cardinality/form and exact configured revision membership. Unsupported selectors return empty HTTP 400 before profile mapping. With a supported selector, the selected profile validates any present _meta before admission and the optional request limiter. For an unsupported notification method with a supported selector, the modern path returns empty HTTP 400; the 2025 path accepts and ignores a well-formed notification with empty HTTP 202, including notifications/roots/list_changed. This acknowledgment does not enable roots, sampling, or other server-initiated calls. Identifiable notifications/cancelled skips parameter and present-_meta validation only, traverses the other stages, and returns empty HTTP 202 on the modern path. Every session-enabled 2025 notification also requires verified session framing and binding before acknowledgment or any active-request effect, so a retired or wrong-owner session receives neutral HTTP 404. Small, valid, owner-verified session controls use the reserved control quota instead of the ordinary request limiter; malformed/oversized or unsupported notifications and session-disabled views keep ordinary limiting. Notifications do not acquire request-only mirrored-header, required-metadata/capability, tool-limiter, queue, interceptor, handler, sanitizer, or response-envelope semantics.

The 2026-07-28 path does not use initialize, an initialization handshake, or a session. When a request is rejected after strict JSON parsing exposes the exact string method: "initialize", the supported-version diagnostic lists the revisions configured on the selected endpoint. On a 2026-only endpoint that list contains only 2026-07-28. UnsupportedProtocolVersionError retains its defined requested field. Pre-JSON failures, unparseable JSON, absent or non-string methods, and other method names do not acquire that diagnostic. Defined request IDs may be reflected; rejected header and metadata values are not echoed.

Every MCP HTTP response contains exactly one Cache-Control: no-store, covering early parser/transport errors, fixed JSON and empty responses, CORS preflight, notifications, and SSE. Application policy cannot replace it with a cacheable value; an attempted Cache-Control response header fails closed. Protocol resource cache hints remain independent.

Implemented 2026-07-28 operation areas

Soklet implements endpoint discovery and framework catalogs; tools; prompts; exact and templated resources; prompt-argument and resource-template Completion; custom resource pagination; multi-round elicitation input; durable Tasks; progress; cooperative request and task cancelation; resource/task subscriptions; and localization-driven tool, prompt, and resource catalog invalidations. Capabilities are derived from each endpoint's immutable registrations, server-level task manager, and localization configuration.

The transport supports JSON responses and request-scoped SSE where a method needs progress or a long-lived subscription. It is not a general bidirectional session channel.

Method or messageOwnership and availability
server/discoverFramework-owned direct discovery for every endpoint
tools/list, tools/callFramework catalog plus selected application tool handler when tools exist
prompts/list, prompts/getFramework catalog plus selected application prompt handler when prompts exist
resources/listFramework static catalog, or the endpoint's sole custom list handler
resources/templates/listFramework catalog of registered templates
resources/readSelected exact or templated application resource handler, or an authorized canonical Skill file
skills/list, skills/getGenerated manifests for programmatically registered Skills; their exact files are served through resources/read
completion/completeConfigured prompt-argument or literal resource-template completer; advertised only when the endpoint has a completer; requires a server-wide request limiter
tasks/getFramework-routed authoritative lookup through the application-owned task manager
tasks/updateFramework validation plus application-owned authorization and idempotent task-input handling
tasks/cancelFramework validation plus application-owned durable cooperative cancelation intent
subscriptions/listenFramework stream for configured resource events, authorized task snapshots when the manager supplies an event publisher, and coarse localization invalidations
notifications/cancelledValidated/admitted/request-limited compatibility notification; acknowledged with empty 202 and otherwise ignored
notifications/progressServer output associated with one request-scoped progress token
Subscription acknowledgment/change notificationsFramework output derived from configured filters, application resource events, task-ID hints followed by fresh authorized lookups, and localization catalog invalidation
notifications/tasksAdvisory current task snapshot on an accepted task subscription; tasks/get remains authoritative
elicitation/createDeclared form or URL elicitation embedded in input_required results

Framework-generated catalogs bypass the application handler interceptor. Configured catalog-access-policy evaluation uses shared handler slots, and built-in paged catalogs on the 2025 revisions also use those slots for framework rendering. See catalog admission limits. Custom resource-list and Skills-list handlers use the application handler pipeline, including its interceptor and slot/queue bounds.

Completion uses the bounded application pipeline, interceptor, request deadline, cooperative cancelation, and eligible request-scoped progress. It returns terminal string suggestions; it cannot create Tasks, request elicitation, or continue a multi-round workflow. Resource references must identify the registered template string, not an expanded URI. Completion requests carry Mcp-Method but omit Mcp-Name. See Argument completion for input validation, neutral target errors, authorization, and limiter requirements.

Apps and host rendering

MCP Apps uses ordinary tools and exact ui:// resources with the text/html;profile=mcp-app MIME type. Soklet publishes their association, projects audience metadata for the current request's Apps capability, and serializes typed CSP/permission hints. The client host owns the renderer, browser sandbox, and tool-call bridge. An Apps-capable host must also support the stateless 2026-07-28 transport; extension support alone is insufficient.

Non-Apps clients retain model-visible tools and their ordinary outputs. Eligible UI resources remain listed in the static resource catalog for both client types; resource listing does not use tool-audience filtering. Custom resource-list handlers can apply an Apps capability check if they want different listing behavior. Audience metadata, capability claims, and listing visibility are not authorization. Exact resource reads and all follow-up tool calls still require current application policy. Authenticated Apps support remains unverified in unmodified Inspector 2.7.0. Test the actual host and authentication route before deployment, and keep useful text output available independently of rendering.

Stable framework error mappings

ConditionHTTP statusJSON-RPC/MCP code
Malformed JSON body400-32700
Invalid JSON-RPC request envelope400-32600
Rate-limit denial429-31999
Strict unknown mirrored header400-31998
Handler capacity exhausted503-32603
Active catalog access-policy deadline504-32603
Intentional application McpJsonRpcException400Authored error code
Queued request deadline503-32603
Active application-handler request deadline200-32603
Framework-owned protocol-operation deadline504bodyless
Required standard/custom header mismatch400-32020
Unsupported protocol version400-32022
Missing required client capability400-32021
Invalid parameters or invalid request state400-32602
Request-state protector unavailable503-32603
Application-execution failure or output/protector contract failure200-32603
Framework policy or pre-dispatch protector contract failure500-32603
Unknown JSON-RPC method404-32601

On mixed-version endpoints, a legacy-shaped request can produce a header mismatch instead of an unsupported-version error. For example, on an endpoint serving 2025-06-18 and 2026-07-28, a legacy ping with MCP-Protocol-Version: 2025-03-26 returns -32020 with data.supportedVersions. With the same legacy framing, initialize with that header instead returns -32022 with data.supported and data.requested, as does a ping naming the recognized but unserved revision 2025-11-25.

Initial subscriptions/listen catalog baselines use these same pre-commit policy mappings: exhausted handler capacity or a policy deadline while queued returns 503; a deadline during active catalog-policy work returns 504; an unrecovered projection failure returns 500. These responses carry the neutral JSON-RPC -32603 error. Once SSE is committed, terminal errors stay in that stream.

Error envelopes preserve an identifiable string or integer request ID. Framework failures suppress unsafe application diagnostics. Notifications suppress error bodies.

Deadline response ownership

Once an application handler owns a request, a pre-commit absolute deadline maps to HTTP 200 with JSON-RPC -32603. A deadline that expires earlier, while Soklet still owns framework protocol work, returns a bodyless HTTP 504 with the normal bounded response headers. Both paths record a DEADLINE_EXCEEDED request outcome.

Intentionally unsupported

Soklet does not provide:

  • stdio transport;
  • public arbitrary JSON Schema authoring or network schema references;
  • MCP Roots or Sampling;
  • the MCP Logging capability;
  • obsolete or proposed Tasks forms such as request-level task, tasks/list, and tasks/result;
  • task augmentation for operations other than tools/call;
  • a Soklet-owned durable task database, queue, scheduler, worker, lease, fencing, retry, or cleanup runtime;
  • mutable tool or prompt registrations and application-owned list-change publishers for them (localization reload still emits framework-owned coarse invalidations);
  • an application result-extension registry;
  • a built-in file-resource mapper;
  • an OAuth authorization server or identity provider; or
  • TLS termination on the MCP listener.

Soklet does not implement MCP Logging. Use application logging and Soklet's observability and OpenTelemetry integrations. Pass file or directory information through explicit tool parameters, resource URIs, or server configuration, and integrate directly with a model provider when needed.

Soklet implements the MCP Tasks extension through an application-provided McpTaskManager. The protocol is interoperable, while persistence and execution remain application-owned. See MCP Tasks and Failures, Retries, And Durable Work.

Application-owned responsibilities

ConcernApplication or deployment owns
Authentication/authorizationCredential verification, principal/partition construction, per-operation business policy, standards-compliant challenges
OAuthRFC 9728 protected-resource metadata with at least one authorization server, challenge/well-known behavior, and every other applicable authorization-server and resource-server obligation; never require offline_access as a protected-resource scope
TLS and proxiesTLS termination, proxy trust, effective client address policy, Host forwarding, network ACLs
Distributed limitsFleet-wide quota state and availability policy
CursorsEncoding, integrity, expiry, authorization binding, snapshot semantics, cross-instance portability
Application-protected stateConfidentiality, integrity, expiry, replay and workflow consumption
Custom framework protectorExact associated-data authentication and secure provider operation
Filesystem resourcesContainment, canonicalization, traversal and symlink policy
Prompt/tool safetyPrompt injection defenses, validation, side-effect authorization, safe client-visible errors
AppsReviewed UI assets, safe DOM rendering, per-operation authorization and redaction, useful text fallback, and verification of the selected host's sandbox and bridge behavior
Completion suggestionsCaller/tenant authorization for every suggestion, meaningful request budgets, locale-sensitive matching, and canonical identifier values
Subscription busesDistributed broadcast delivery for resource and task events if process-local delivery is insufficient; reconnect reconciliation and any durable replay log
Task backendDurable task/origin storage, authorization binding, legal atomic transitions, retention, cleanup, and a stable event-publisher property
Task executionWork queues, worker leases and fencing, checkpoints, retry policy, idempotency, and recovery of external side effects
Ambiguous retriesStable application idempotency keys and lookup/deduplication when a task-creation response may have been lost
TelemetryCollector performance, sensitive Throwable/log handling, retention and export policy

Soklet transports application-owned authentication decisions and safe Bearer challenges. BearerAuthenticationChallenge validates and constructs the header value, including an absolute resource_metadata URI and operation scopes. The application owns that URI, authorization-server selection, scope meanings, and its other standards obligations. Soklet does not publish protected-resource metadata or choose an authorization server, and using admission to emit a challenge does not alone establish complete MCP Authorization conformance.

For implementation guidance, see MCP Tasks, Input and Request State, Prompts and Resources, and Production Readiness.

Previous
Observability and Testing