claude-agent-sdk 0.1.3 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +9 -2
- data/lib/claude_agent_sdk/sdk_mcp_server.rb +206 -18
- data/lib/claude_agent_sdk/version.rb +1 -1
- data/lib/claude_agent_sdk.rb +6 -3
- metadata +17 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: fe94c46bcf37e8f5fd38dcc5ccaa17e3490d70f79b083ffd4f753711e8df38ab
         | 
| 4 | 
            +
              data.tar.gz: ff8fd7d82daa4acac453b15c727b96c03edf8fa2f1d52c772b75b24cd0df2792
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 597dd01120488fdd74c18c2ac0623bcb7d9f0f9af784cc868a291e3075a25a999023258acf338210e7e0f2d0d2ed3de5512cce8e5c72fb0b29142c665d8ab2ac
         | 
| 7 | 
            +
              data.tar.gz: a3f2c72a4beac29ba34471bbf7195e71f92720afc220d2c52250421f49da4bedc3ce8be113e8a1c75fb9a370418528d7912f71343fe7acebe81be26abbc9d32f
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file. | |
| 5 5 | 
             
            The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
         | 
| 6 6 | 
             
            and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
         | 
| 7 7 |  | 
| 8 | 
            +
            ## [0.2.0] - 2025-10-17
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ### Changed
         | 
| 11 | 
            +
            - **BREAKING:** Updated minimum Ruby version from 3.0+ to 3.2+ (required by official MCP SDK)
         | 
| 12 | 
            +
            - **Major refactoring:** SDK MCP server now uses official Ruby MCP SDK (`mcp` gem v0.4) internally
         | 
| 13 | 
            +
            - Internal implementation migrated from custom MCP to wrapping official `MCP::Server`
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ### Added
         | 
| 16 | 
            +
            - Official Ruby MCP SDK (`mcp` gem) as runtime dependency
         | 
| 17 | 
            +
            - Full MCP protocol compliance via official SDK
         | 
| 18 | 
            +
            - `handle_json` method for protocol-compliant JSON-RPC handling
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ### Improved
         | 
| 21 | 
            +
            - Better long-term maintenance by leveraging official SDK updates
         | 
| 22 | 
            +
            - Aligned with Python SDK implementation pattern (using official MCP library)
         | 
| 23 | 
            +
            - All 86 tests passing with full backward compatibility maintained
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ### Technical Details
         | 
| 26 | 
            +
            - Creates dynamic `MCP::Tool`, `MCP::Resource`, and `MCP::Prompt` classes from block-based definitions
         | 
| 27 | 
            +
            - User-facing API remains unchanged - no breaking changes for Ruby 3.2+ users
         | 
| 28 | 
            +
            - Maintains backward-compatible methods (`list_tools`, `call_tool`, etc.)
         | 
| 29 | 
            +
             | 
| 8 30 | 
             
            ## [0.1.3] - 2025-10-15
         | 
| 9 31 |  | 
| 10 32 | 
             
            ### Added
         | 
    
        data/README.md
    CHANGED
    
    | @@ -29,7 +29,7 @@ gem install claude-agent-sdk | |
| 29 29 | 
             
            ```
         | 
| 30 30 |  | 
| 31 31 | 
             
            **Prerequisites:**
         | 
| 32 | 
            -
            - Ruby 3. | 
| 32 | 
            +
            - Ruby 3.2+
         | 
| 33 33 | 
             
            - Node.js
         | 
| 34 34 | 
             
            - Claude Code 2.0.0+: `npm install -g @anthropic-ai/claude-code`
         | 
| 35 35 |  | 
| @@ -131,7 +131,11 @@ For a complete example, see [examples/streaming_input_example.rb](examples/strea | |
| 131 131 |  | 
| 132 132 | 
             
            ## Client
         | 
| 133 133 |  | 
| 134 | 
            -
            `ClaudeAgentSDK::Client` supports bidirectional, interactive conversations with Claude Code. Unlike `query()`, `Client` enables **custom tools**, **hooks**, and **permission callbacks**, all of which can be defined as Ruby procs/lambdas. | 
| 134 | 
            +
            `ClaudeAgentSDK::Client` supports bidirectional, interactive conversations with Claude Code. Unlike `query()`, `Client` enables **custom tools**, **hooks**, and **permission callbacks**, all of which can be defined as Ruby procs/lambdas.
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            **The Client class automatically uses streaming mode** for bidirectional communication, allowing you to send multiple queries dynamically during a single session without closing the connection. This matches the Python SDK's `ClaudeSDKClient` behavior.
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            See [lib/claude_agent_sdk.rb](lib/claude_agent_sdk.rb) for implementation details.
         | 
| 135 139 |  | 
| 136 140 | 
             
            ### Custom Tools (SDK MCP Servers)
         | 
| 137 141 |  | 
| @@ -139,6 +143,8 @@ A **custom tool** is a Ruby proc/lambda that you can offer to Claude, for Claude | |
| 139 143 |  | 
| 140 144 | 
             
            Custom tools are implemented as in-process MCP servers that run directly within your Ruby application, eliminating the need for separate processes that regular MCP servers require.
         | 
| 141 145 |  | 
| 146 | 
            +
            **Implementation**: This SDK uses the [official Ruby MCP SDK](https://github.com/modelcontextprotocol/ruby-sdk) (`mcp` gem) internally, providing full protocol compliance while offering a simpler block-based API for tool definition.
         | 
| 147 | 
            +
             | 
| 142 148 | 
             
            For a complete example, see [examples/mcp_calculator.rb](examples/mcp_calculator.rb).
         | 
| 143 149 |  | 
| 144 150 | 
             
            #### Creating a Simple Tool
         | 
| @@ -292,6 +298,7 @@ Async do | |
| 292 298 | 
             
              client = ClaudeAgentSDK::Client.new
         | 
| 293 299 |  | 
| 294 300 | 
             
              begin
         | 
| 301 | 
            +
                # Connect automatically uses streaming mode for bidirectional communication
         | 
| 295 302 | 
             
                client.connect
         | 
| 296 303 |  | 
| 297 304 | 
             
                # Send a query
         | 
| @@ -1,18 +1,18 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'mcp'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module ClaudeAgentSDK
         | 
| 4 | 
            -
              # SDK MCP Server -  | 
| 6 | 
            +
              # SDK MCP Server - wraps official MCP::Server with block-based API
         | 
| 5 7 | 
             
              #
         | 
| 6 8 | 
             
              # Unlike external MCP servers that run as separate processes, SDK MCP servers
         | 
| 7 9 | 
             
              # run directly in your application's process, providing better performance
         | 
| 8 10 | 
             
              # and simpler deployment.
         | 
| 9 11 | 
             
              #
         | 
| 10 | 
            -
              #  | 
| 11 | 
            -
              #  | 
| 12 | 
            -
              # - Resources: Data sources that can be read (files, databases, APIs, etc.)
         | 
| 13 | 
            -
              # - Prompts: Reusable prompt templates with arguments
         | 
| 12 | 
            +
              # This class wraps the official MCP Ruby SDK and provides a simpler block-based
         | 
| 13 | 
            +
              # API for defining tools, resources, and prompts.
         | 
| 14 14 | 
             
              class SdkMcpServer
         | 
| 15 | 
            -
                attr_reader :name, :version, :tools, :resources, :prompts
         | 
| 15 | 
            +
                attr_reader :name, :version, :tools, :resources, :prompts, :mcp_server
         | 
| 16 16 |  | 
| 17 17 | 
             
                def initialize(name:, version: '1.0.0', tools: [], resources: [], prompts: [])
         | 
| 18 18 | 
             
                  @name = name
         | 
| @@ -20,12 +20,34 @@ module ClaudeAgentSDK | |
| 20 20 | 
             
                  @tools = tools
         | 
| 21 21 | 
             
                  @resources = resources
         | 
| 22 22 | 
             
                  @prompts = prompts
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                   | 
| 25 | 
            -
                   | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # Create dynamic Tool classes from tool definitions
         | 
| 25 | 
            +
                  tool_classes = create_tool_classes(tools)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  # Create dynamic Resource classes from resource definitions
         | 
| 28 | 
            +
                  resource_classes = create_resource_classes(resources)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # Create dynamic Prompt classes from prompt definitions
         | 
| 31 | 
            +
                  prompt_classes = create_prompt_classes(prompts)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  # Create the official MCP::Server instance
         | 
| 34 | 
            +
                  @mcp_server = MCP::Server.new(
         | 
| 35 | 
            +
                    name: name,
         | 
| 36 | 
            +
                    version: version,
         | 
| 37 | 
            +
                    tools: tool_classes,
         | 
| 38 | 
            +
                    resources: resource_classes,
         | 
| 39 | 
            +
                    prompts: prompt_classes
         | 
| 40 | 
            +
                  )
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                # Handle a JSON-RPC request
         | 
| 44 | 
            +
                # @param json_string [String] JSON-RPC request
         | 
| 45 | 
            +
                # @return [String] JSON-RPC response
         | 
| 46 | 
            +
                def handle_json(json_string)
         | 
| 47 | 
            +
                  @mcp_server.handle_json(json_string)
         | 
| 26 48 | 
             
                end
         | 
| 27 49 |  | 
| 28 | 
            -
                # List all available tools
         | 
| 50 | 
            +
                # List all available tools (for backward compatibility)
         | 
| 29 51 | 
             
                # @return [Array<Hash>] Array of tool definitions
         | 
| 30 52 | 
             
                def list_tools
         | 
| 31 53 | 
             
                  @tools.map do |tool|
         | 
| @@ -37,12 +59,12 @@ module ClaudeAgentSDK | |
| 37 59 | 
             
                  end
         | 
| 38 60 | 
             
                end
         | 
| 39 61 |  | 
| 40 | 
            -
                # Execute a tool by name
         | 
| 62 | 
            +
                # Execute a tool by name (for backward compatibility)
         | 
| 41 63 | 
             
                # @param name [String] Tool name
         | 
| 42 64 | 
             
                # @param arguments [Hash] Tool arguments
         | 
| 43 65 | 
             
                # @return [Hash] Tool result
         | 
| 44 66 | 
             
                def call_tool(name, arguments)
         | 
| 45 | 
            -
                  tool = @ | 
| 67 | 
            +
                  tool = @tools.find { |t| t.name == name }
         | 
| 46 68 | 
             
                  raise "Tool '#{name}' not found" unless tool
         | 
| 47 69 |  | 
| 48 70 | 
             
                  # Call the tool's handler
         | 
| @@ -56,7 +78,7 @@ module ClaudeAgentSDK | |
| 56 78 | 
             
                  result
         | 
| 57 79 | 
             
                end
         | 
| 58 80 |  | 
| 59 | 
            -
                # List all available resources
         | 
| 81 | 
            +
                # List all available resources (for backward compatibility)
         | 
| 60 82 | 
             
                # @return [Array<Hash>] Array of resource definitions
         | 
| 61 83 | 
             
                def list_resources
         | 
| 62 84 | 
             
                  @resources.map do |resource|
         | 
| @@ -69,11 +91,11 @@ module ClaudeAgentSDK | |
| 69 91 | 
             
                  end
         | 
| 70 92 | 
             
                end
         | 
| 71 93 |  | 
| 72 | 
            -
                # Read a resource by URI
         | 
| 94 | 
            +
                # Read a resource by URI (for backward compatibility)
         | 
| 73 95 | 
             
                # @param uri [String] Resource URI
         | 
| 74 96 | 
             
                # @return [Hash] Resource content
         | 
| 75 97 | 
             
                def read_resource(uri)
         | 
| 76 | 
            -
                  resource = @ | 
| 98 | 
            +
                  resource = @resources.find { |r| r.uri == uri }
         | 
| 77 99 | 
             
                  raise "Resource '#{uri}' not found" unless resource
         | 
| 78 100 |  | 
| 79 101 | 
             
                  # Call the resource's reader
         | 
| @@ -87,7 +109,7 @@ module ClaudeAgentSDK | |
| 87 109 | 
             
                  content
         | 
| 88 110 | 
             
                end
         | 
| 89 111 |  | 
| 90 | 
            -
                # List all available prompts
         | 
| 112 | 
            +
                # List all available prompts (for backward compatibility)
         | 
| 91 113 | 
             
                # @return [Array<Hash>] Array of prompt definitions
         | 
| 92 114 | 
             
                def list_prompts
         | 
| 93 115 | 
             
                  @prompts.map do |prompt|
         | 
| @@ -99,12 +121,12 @@ module ClaudeAgentSDK | |
| 99 121 | 
             
                  end
         | 
| 100 122 | 
             
                end
         | 
| 101 123 |  | 
| 102 | 
            -
                # Get a prompt by name
         | 
| 124 | 
            +
                # Get a prompt by name (for backward compatibility)
         | 
| 103 125 | 
             
                # @param name [String] Prompt name
         | 
| 104 126 | 
             
                # @param arguments [Hash] Arguments to fill in the prompt template
         | 
| 105 127 | 
             
                # @return [Hash] Prompt with filled-in arguments
         | 
| 106 128 | 
             
                def get_prompt(name, arguments = {})
         | 
| 107 | 
            -
                  prompt = @ | 
| 129 | 
            +
                  prompt = @prompts.find { |p| p.name == name }
         | 
| 108 130 | 
             
                  raise "Prompt '#{name}' not found" unless prompt
         | 
| 109 131 |  | 
| 110 132 | 
             
                  # Call the prompt's generator
         | 
| @@ -120,6 +142,172 @@ module ClaudeAgentSDK | |
| 120 142 |  | 
| 121 143 | 
             
                private
         | 
| 122 144 |  | 
| 145 | 
            +
                # Create dynamic Tool classes from tool definitions
         | 
| 146 | 
            +
                def create_tool_classes(tools)
         | 
| 147 | 
            +
                  tools.map do |tool_def|
         | 
| 148 | 
            +
                    # Create a new class that extends MCP::Tool
         | 
| 149 | 
            +
                    Class.new(MCP::Tool) do
         | 
| 150 | 
            +
                      @tool_def = tool_def
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                      class << self
         | 
| 153 | 
            +
                        attr_reader :tool_def
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                        def description
         | 
| 156 | 
            +
                          @tool_def.description
         | 
| 157 | 
            +
                        end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                        def input_schema
         | 
| 160 | 
            +
                          convert_schema(@tool_def.input_schema)
         | 
| 161 | 
            +
                        end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                        def call(server_context: nil, **args)
         | 
| 164 | 
            +
                          # Filter out server_context and pass remaining args to handler
         | 
| 165 | 
            +
                          result = @tool_def.handler.call(args)
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                          # Convert result to MCP::Tool::Response format
         | 
| 168 | 
            +
                          content = result[:content].map do |item|
         | 
| 169 | 
            +
                            {
         | 
| 170 | 
            +
                              type: item[:type],
         | 
| 171 | 
            +
                              text: item[:text]
         | 
| 172 | 
            +
                            }
         | 
| 173 | 
            +
                          end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                          MCP::Tool::Response.new(content)
         | 
| 176 | 
            +
                        end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                        private
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                        def convert_schema(schema)
         | 
| 181 | 
            +
                          # If it's already a proper JSON schema, return it
         | 
| 182 | 
            +
                          if schema.is_a?(Hash) && schema[:type] && schema[:properties]
         | 
| 183 | 
            +
                            return schema
         | 
| 184 | 
            +
                          end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                          # Simple schema: hash mapping parameter names to types
         | 
| 187 | 
            +
                          if schema.is_a?(Hash)
         | 
| 188 | 
            +
                            properties = {}
         | 
| 189 | 
            +
                            schema.each do |param_name, param_type|
         | 
| 190 | 
            +
                              properties[param_name] = type_to_json_schema(param_type)
         | 
| 191 | 
            +
                            end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                            return {
         | 
| 194 | 
            +
                              type: 'object',
         | 
| 195 | 
            +
                              properties: properties,
         | 
| 196 | 
            +
                              required: properties.keys.map(&:to_s)
         | 
| 197 | 
            +
                            }
         | 
| 198 | 
            +
                          end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                          # Default fallback
         | 
| 201 | 
            +
                          { type: 'object', properties: {} }
         | 
| 202 | 
            +
                        end
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                        def type_to_json_schema(type)
         | 
| 205 | 
            +
                          case type
         | 
| 206 | 
            +
                          when :string, String
         | 
| 207 | 
            +
                            { type: 'string' }
         | 
| 208 | 
            +
                          when :integer, Integer
         | 
| 209 | 
            +
                            { type: 'integer' }
         | 
| 210 | 
            +
                          when :float, Float
         | 
| 211 | 
            +
                            { type: 'number' }
         | 
| 212 | 
            +
                          when :boolean, TrueClass, FalseClass
         | 
| 213 | 
            +
                            { type: 'boolean' }
         | 
| 214 | 
            +
                          when :number
         | 
| 215 | 
            +
                            { type: 'number' }
         | 
| 216 | 
            +
                          else
         | 
| 217 | 
            +
                            { type: 'string' } # Default fallback
         | 
| 218 | 
            +
                          end
         | 
| 219 | 
            +
                        end
         | 
| 220 | 
            +
                      end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                      # Set the tool name
         | 
| 223 | 
            +
                      define_singleton_method(:name) { @tool_def.name }
         | 
| 224 | 
            +
                    end
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
                end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                # Create dynamic Resource classes from resource definitions
         | 
| 229 | 
            +
                def create_resource_classes(resources)
         | 
| 230 | 
            +
                  resources.map do |resource_def|
         | 
| 231 | 
            +
                    # Create a new class that extends MCP::Resource
         | 
| 232 | 
            +
                    Class.new(MCP::Resource) do
         | 
| 233 | 
            +
                      @resource_def = resource_def
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                      class << self
         | 
| 236 | 
            +
                        attr_reader :resource_def
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                        def uri
         | 
| 239 | 
            +
                          @resource_def.uri
         | 
| 240 | 
            +
                        end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                        def name
         | 
| 243 | 
            +
                          @resource_def.name
         | 
| 244 | 
            +
                        end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                        def description
         | 
| 247 | 
            +
                          @resource_def.description
         | 
| 248 | 
            +
                        end
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                        def mime_type
         | 
| 251 | 
            +
                          @resource_def.mime_type
         | 
| 252 | 
            +
                        end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                        def read
         | 
| 255 | 
            +
                          result = @resource_def.reader.call
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                          # Convert to MCP format
         | 
| 258 | 
            +
                          result[:contents].map do |content|
         | 
| 259 | 
            +
                            MCP::ResourceContents.new(
         | 
| 260 | 
            +
                              uri: content[:uri],
         | 
| 261 | 
            +
                              mime_type: content[:mimeType] || content[:mime_type],
         | 
| 262 | 
            +
                              text: content[:text]
         | 
| 263 | 
            +
                            )
         | 
| 264 | 
            +
                          end
         | 
| 265 | 
            +
                        end
         | 
| 266 | 
            +
                      end
         | 
| 267 | 
            +
                    end
         | 
| 268 | 
            +
                  end
         | 
| 269 | 
            +
                end
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                # Create dynamic Prompt classes from prompt definitions
         | 
| 272 | 
            +
                def create_prompt_classes(prompts)
         | 
| 273 | 
            +
                  prompts.map do |prompt_def|
         | 
| 274 | 
            +
                    # Create a new class that extends MCP::Prompt
         | 
| 275 | 
            +
                    Class.new(MCP::Prompt) do
         | 
| 276 | 
            +
                      @prompt_def = prompt_def
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                      class << self
         | 
| 279 | 
            +
                        attr_reader :prompt_def
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                        def name
         | 
| 282 | 
            +
                          @prompt_def.name
         | 
| 283 | 
            +
                        end
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                        def description
         | 
| 286 | 
            +
                          @prompt_def.description
         | 
| 287 | 
            +
                        end
         | 
| 288 | 
            +
             | 
| 289 | 
            +
                        def arguments
         | 
| 290 | 
            +
                          @prompt_def.arguments || []
         | 
| 291 | 
            +
                        end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                        def get(**args)
         | 
| 294 | 
            +
                          result = @prompt_def.generator.call(args)
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                          # Convert to MCP format
         | 
| 297 | 
            +
                          {
         | 
| 298 | 
            +
                            messages: result[:messages].map do |msg|
         | 
| 299 | 
            +
                              {
         | 
| 300 | 
            +
                                role: msg[:role],
         | 
| 301 | 
            +
                                content: msg[:content]
         | 
| 302 | 
            +
                              }
         | 
| 303 | 
            +
                            end
         | 
| 304 | 
            +
                          }
         | 
| 305 | 
            +
                        end
         | 
| 306 | 
            +
                      end
         | 
| 307 | 
            +
                    end
         | 
| 308 | 
            +
                  end
         | 
| 309 | 
            +
                end
         | 
| 310 | 
            +
             | 
| 123 311 | 
             
                def convert_input_schema(schema)
         | 
| 124 312 | 
             
                  # If it's already a proper JSON schema, return it
         | 
| 125 313 | 
             
                  if schema.is_a?(Hash) && schema[:type] && schema[:properties]
         | 
    
        data/lib/claude_agent_sdk.rb
    CHANGED
    
    | @@ -86,11 +86,12 @@ module ClaudeAgentSDK | |
| 86 86 | 
             
              #
         | 
| 87 87 | 
             
              # This client provides full control over the conversation flow with support
         | 
| 88 88 | 
             
              # for streaming, hooks, permission callbacks, and dynamic message sending.
         | 
| 89 | 
            +
              # The Client class always uses streaming mode for bidirectional communication.
         | 
| 89 90 | 
             
              #
         | 
| 90 91 | 
             
              # @example Basic usage
         | 
| 91 92 | 
             
              #   Async do
         | 
| 92 93 | 
             
              #     client = ClaudeAgentSDK::Client.new
         | 
| 93 | 
            -
              #     client.connect
         | 
| 94 | 
            +
              #     client.connect  # No arguments needed - automatically uses streaming mode
         | 
| 94 95 | 
             
              #
         | 
| 95 96 | 
             
              #     client.query("What is the capital of France?")
         | 
| 96 97 | 
             
              #     client.receive_response do |msg|
         | 
| @@ -150,8 +151,10 @@ module ClaudeAgentSDK | |
| 150 151 | 
             
                    configured_options = @options.dup_with(permission_prompt_tool_name: 'stdio')
         | 
| 151 152 | 
             
                  end
         | 
| 152 153 |  | 
| 153 | 
            -
                  #  | 
| 154 | 
            -
                   | 
| 154 | 
            +
                  # Auto-connect with empty enumerator if no prompt is provided
         | 
| 155 | 
            +
                  # This matches the Python SDK pattern where ClaudeSDKClient always uses streaming mode
         | 
| 156 | 
            +
                  # An empty enumerator keeps stdin open for bidirectional communication
         | 
| 157 | 
            +
                  actual_prompt = prompt || [].to_enum
         | 
| 155 158 | 
             
                  @transport = SubprocessCLITransport.new(actual_prompt, configured_options)
         | 
| 156 159 | 
             
                  @transport.connect
         | 
| 157 160 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: claude-agent-sdk
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Community Contributors
         | 
| 8 8 | 
             
            bindir: bin
         | 
| 9 9 | 
             
            cert_chain: []
         | 
| 10 | 
            -
            date: 2025-10- | 
| 10 | 
            +
            date: 2025-10-17 00:00:00.000000000 Z
         | 
| 11 11 | 
             
            dependencies:
         | 
| 12 12 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 13 13 | 
             
              name: async
         | 
| @@ -23,6 +23,20 @@ dependencies: | |
| 23 23 | 
             
                - - "~>"
         | 
| 24 24 | 
             
                  - !ruby/object:Gem::Version
         | 
| 25 25 | 
             
                    version: '2.0'
         | 
| 26 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 27 | 
            +
              name: mcp
         | 
| 28 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 29 | 
            +
                requirements:
         | 
| 30 | 
            +
                - - "~>"
         | 
| 31 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            +
                    version: '0.4'
         | 
| 33 | 
            +
              type: :runtime
         | 
| 34 | 
            +
              prerelease: false
         | 
| 35 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 36 | 
            +
                requirements:
         | 
| 37 | 
            +
                - - "~>"
         | 
| 38 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 39 | 
            +
                    version: '0.4'
         | 
| 26 40 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 27 41 | 
             
              name: bundler
         | 
| 28 42 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -114,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 114 128 | 
             
              requirements:
         | 
| 115 129 | 
             
              - - ">="
         | 
| 116 130 | 
             
                - !ruby/object:Gem::Version
         | 
| 117 | 
            -
                  version: 3. | 
| 131 | 
            +
                  version: 3.2.0
         | 
| 118 132 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 119 133 | 
             
              requirements:
         | 
| 120 134 | 
             
              - - ">="
         |