Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions core/src/main/scala/chimp/protocol/Subscriptions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package chimp.protocol

import io.circe.{Codec, Json}

/** The notification types a client opts into on a `subscriptions/listen` stream (2026-07-28). Each type is opt-in: the server MUST NOT send
* a type the client has not requested. `resourceSubscriptions` replaces the former `resources/subscribe` RPC.
*/
final case class SubscriptionFilter(
promptsListChanged: Option[Boolean] = None,
resourceSubscriptions: Option[List[String]] = None,
resourcesListChanged: Option[Boolean] = None,
toolsListChanged: Option[Boolean] = None
) derives Codec

/** Params of a `subscriptions/listen` request: the notification filter the client opts into on the stream. */
final case class SubscriptionsListenParams(notifications: SubscriptionFilter, _meta: Option[Map[String, Json]] = None) derives Codec

final case class SubscriptionsListenRequest(method: String = "subscriptions/listen", params: SubscriptionsListenParams) derives Codec

/** Result of `subscriptions/listen`, sent only when the server tears the subscription down gracefully (e.g. on shutdown); the body is
* otherwise empty. The subscription id travels in `_meta` under `io.modelcontextprotocol/subscriptionId`.
*/
final case class SubscriptionsListenResult(resultType: ResultType = ResultType.Complete, _meta: Option[Map[String, Json]] = None)
derives Codec

/** Params of the `notifications/subscriptions/acknowledged` notification: the subset of requested notification types the server will honor.
*/
final case class SubscriptionsAcknowledgedParams(notifications: SubscriptionFilter, _meta: Option[Map[String, Json]] = None) derives Codec

/** The `notifications/subscriptions/acknowledged` notification the server sends first on a listen stream. */
final case class SubscriptionsAcknowledgedNotification(
method: String = "notifications/subscriptions/acknowledged",
params: SubscriptionsAcknowledgedParams
) derives Codec
1 change: 1 addition & 0 deletions core/src/main/scala/chimp/protocol/Versioning.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ object ProtocolMeta:
val ClientInfo: String = "io.modelcontextprotocol/clientInfo"
val ClientCapabilities: String = "io.modelcontextprotocol/clientCapabilities"
val ServerInfo: String = "io.modelcontextprotocol/serverInfo"
val SubscriptionId: String = "io.modelcontextprotocol/subscriptionId"

/** An `UnsupportedProtocolVersion` error (`-32022`) naming the versions the server supports, so the client can retry with one of them. */
def unsupportedVersionError(requested: String, supported: List[String]): JSONRPCErrorObject =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,37 @@ class Schema20260728ConformanceSpec extends SchemaConformance:
val msg: JSONRPCMessage =
JSONRPCMessage.Error(id = RequestId(1), error = ProtocolMeta.unsupportedVersionError("1900-01-01", List("2026-07-28", "2025-11-25")))
validate("UnsupportedProtocolVersionError", msg)

it should "produce a SubscriptionFilter that matches the spec schema" in:
validate(
"SubscriptionFilter",
SubscriptionFilter(resourceSubscriptions = Some(List("file:///x")), resourcesListChanged = Some(true), toolsListChanged = Some(false))
)

it should "produce SubscriptionsListenRequestParams that match the spec schema" in:
validate(
"SubscriptionsListenRequestParams",
SubscriptionsListenParams(
notifications = SubscriptionFilter(resourcesListChanged = Some(true)),
_meta = Some(Map(ProtocolMeta.ProtocolVersionKey -> "2026-07-28".asJson, ProtocolMeta.ClientCapabilities -> io.circe.Json.obj()))
)
)

it should "produce a SubscriptionsListenResult that matches the spec schema" in:
validate(
"SubscriptionsListenResult",
SubscriptionsListenResult(_meta =
Some(
Map(
ProtocolMeta.ServerInfo -> Implementation(name = "chimp", version = "1.0").asJson.deepDropNullValues,
ProtocolMeta.SubscriptionId -> "sub-1".asJson
)
)
)
)

it should "produce SubscriptionsAcknowledgedNotificationParams that match the spec schema" in:
validate(
"SubscriptionsAcknowledgedNotificationParams",
SubscriptionsAcknowledgedParams(notifications = SubscriptionFilter(promptsListChanged = Some(true)))
)
Loading