Revision history for MCP::Server

0.4.0  2026-08-09T19:42:11+01:00
    - New public MCP::Server.notify(%notification): the delivery half of .log
      on its own. Takes a whole notification hash (as
      MCP::Server::Protocol's `notification` sub builds it), routes it exactly
      as .log does -- a modern request's own channel, else the legacy rules
      and the shared transport -- and returns True if some channel took it.
      Unlike .log it never echoes to $*ERR and applies no level gating, so a
      background worker can push progress or job output to a client without
      spraying the host process's terminal; callers gate themselves against
      $*MCP-REQUEST-CONTEXT.wants-log. .log now delegates its delivery to it,
      with its echo and gating unchanged.
    - Spec fix: notifications/message params now carry the log line as `data`
      rather than `message`. LoggingMessageNotificationParams has always been
      { level, logger?, data } -- the server was inventing a key, and a client
      reading the spec's one (MCP::Client's on-log hook, among others) saw an
      undefined payload.
    - MCP::Server::Transport::Stdio now serialises write-message with a Lock,
      and the Transport role documents that requirement: writes come from the
      run loop and from any thread that logs or notifies, and a spliced line
      is a stream a JSON-RPC client cannot resynchronise.
    - Server-side elicitation: a tool, resource or prompt handler can now call
      $*MCP-REQUEST-CONTEXT.elicit(...) to ask the human on the other end of
      the client a question and block until they answer. This implements the
      2026-07-28 multi round-trip request pattern (MRTR): the call is answered
      with resultType "input_required", an inputRequests map and an opaque
      requestState, and the client's retry resumes it. New
      MCP::Server::Elicitation (Outcome / Broker / Table).
    - The handler is parked rather than restarted: it keeps running on a thread
      of its own and blocks in await, so nothing it has already done is done
      twice. Only a modern-era request on tools/call, resources/read or
      prompts/get from a client that declared the elicitation capability is
      dispatched that way; every other request is handled exactly as before,
      synchronously, on the caller's thread.
    - New MCP::Server attributes: :&on-elicit (a local fallback for legacy
      clients, the LLM bridge, or direct calls -- takes an ElicitRequest,
      returns an ElicitResult), :$elicitation-ttl (default 300s) and
      :$max-pending-elicitations (default 64), plus .pending-elicitations for
      health checks. A wire client that can be asked always beats the callback.
    - execute-tool-calls now binds a legacy-era $*MCP-REQUEST-CONTEXT around
      each tool call. Tools that read the request context used to die on an
      undefined dynamic variable when a model called them through the bridge.
    - Modern results with resultType "input_required" are no longer stamped
      with ttlMs/cacheScope: a question about a resource is not the resource,
      and it carries a single-use continuation token.
    - tools-for-llm now sorts its declarations by tool name, as tools/list
      already did. Hash order is not stable in Raku, so the tool block a
      model was shown could differ run to run -- and disagree with what a
      client built on tools/list publishes for the same server.
    - execute-tool-calls now treats an empty or whitespace-only arguments
      string as "no arguments" rather than answering with an
      "Invalid tool arguments JSON" error result. Models routinely send ""
      as the arguments of a tool that takes none. Anything else that is not
      a JSON object is still an error result.
    - MCP::Server::HTTP now notices a client hanging up while a handler is
      running, so $*MCP-REQUEST-CONTEXT.cancelled actually flips for the
      case it exists to serve. Previously only a failing write told the
      transport the client had gone, which for a quiet handler was when it
      finally answered -- too late to cancel anything. New :$disconnect-poll
      (default 0.25s) sets how often the client is checked on; the check is
      a zero-byte write, so it puts nothing on the wire.

0.3.0  2026-08-07T12:10:18+01:00
    - Toolkit system: new MCP::Server::Toolkit role plus
      $server.plug($kit, :prefix<...>) and the MCP::Server::Registrar facade.
      Prefixed tools and prompts become "prefix_name"; prefixed resource URIs
      become "scheme://prefix/path".
    - Tool groups now join the prefix and the name with "_" rather than "/", so
      generated names stay inside the MCP tool-name charset. This is a breaking
      change: tool-group 'file' now registers file_read, not file/read.
      ToolGroup remains available as an alias of MCP::Server::Registrar.
    - Duplicate tool names, duplicate prompt names and duplicate resource URIs
      now die instead of silently overwriting, as do tool names outside
      [A-Za-z0-9_-] or longer than 128 characters.
    - MCP::Server.new(:tools[...]) loads toolkits by name (bare names resolve
      under MCP::Server::Tool::), by instance, or as name => config pairs;
      MCP::Server.from-config($path) builds an entire server from a JSON file.
    - New raku-mcp command (MCP::Server::CLI) supporting --config, repeatable
      --tool, --describe and --help.
    - mcp classes (MCP::Server::DSL) are now toolkits themselves and can be
      plugged into a larger server; their .server is private and built lazily.
    - Dual-era MCP protocol support: both the 2025-11-25 (legacy) and
      2026-07-28 (modern) protocol versions are served side by side, with the
      era auto-detected per message -- no constructor flag required.
    - server/discover is now a mandatory method in the modern era.
    - Modern-era results carry a resultType, a _meta block with serverInfo,
      and ttlMs/cacheScope cache metadata on tools/resources/prompts list and
      resource read results.
    - New JSON-RPC error codes -32020, -32021 and -32022 for modern-era
      protocol violations.
    - Per-request _meta logLevel replaces the logging capability in the
      modern era; logging/setLevel is now actually implemented for legacy
      clients (previously a stub).
    - tools/resources/prompts list results are now returned in a
      deterministic order.
    - New MCP::Server::HTTP transport (Cro::HTTP-based Streamable HTTP,
      modern-era only) answers each request with either a JSON body or a
      per-request SSE stream, validates the Origin header, and exposes a
      routes embedding hook for mounting inside a larger Cro app. raku-mcp
      gained --http, --host, --http-path and --allow-origin flags plus a
      matching "http" config-file section.
    - New MCP::Server.new options :protocol-versions, :discovery-ttl-ms and
      :cache-scope, plus per-resource :ttl-ms and :cache-scope.
    - New transport-facing API: handle-modern-request, server-info,
      discovery-document and modern-protocol-versions.
    - New dependencies: Cro::HTTP and MIME::Base64.

0.2.0  2026-06-22T23:32:43+01:00
    - execute-tool-calls now accepts function arguments supplied as
      either a JSON string or an associative object, and returns an
      `is_error` flag on malformed arguments, unknown tools, and
      handler failures.

0.1.3  2026-04-29T23:51:53+01:00
    - Bump Github actions to use node 24+

0.1.2  2026-04-19T10:21:15+01:00
    - added DSL for MCP::Server (shout-out to zef:FCO)

0.1.1  2026-04-09T12:37:47+01:00
    - tools-for-llm: convert registered tools to OpenAI function-calling format
    - execute-tool-calls: route LLM tool call requests to registered handlers
    - Tool group support with / prefix convention

0.1.0  2026-04-09T12:23:43+01:00
    - Initial release
    - MCP (Model Context Protocol) server framework for Raku
    - JSON-RPC 2.0 protocol handling with full error codes
    - Tool registration with JSON Schema generation and parameter validation
    - Resource registration with URI-based access
    - Prompt registration with argument support
    - Stdio transport (stdin/stdout)
    - Pluggable transport architecture via Transport role
    - Examples: echo server, weather server (wttr.in), file server, strawberry counter
