firestore-https-ruby 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a2a2f507167e36197b1f31f02abe19759531f8115c22f225e3a4ee1c1186a555
4
+ data.tar.gz: 7cb925baacab72c49c5a7c9a9e742d54b76c115bcbba99719e96d5ac3ce5393a
5
+ SHA512:
6
+ metadata.gz: 2f8aae71fd7d00a23107f6f3e47faece9ad4e0eeae1caedbc23c43eba2b1fc8f11b379596b699dc0edb91f5bb3336bc4158b9b45a89d2502cff88cea23b32920
7
+ data.tar.gz: 6e655a335e5e4d828db85f3687b260ee86556b1f01c05688dbb1cd2b680aa279dd9715c8cc3cb99bd48599e0cd904aaa106a59f1db163487adfbe1e434f7d2b1
data/GEMINI.md ADDED
@@ -0,0 +1,75 @@
1
+ # Gemini Code Assistant Context
2
+
3
+ This document provides context for the Gemini Code Assistant to understand the project and assist in development.
4
+
5
+ ## Project Overview
6
+
7
+ This is a **Ruby based Model Context Protocol (MCP) server**. It is designed to expose tools over a streaming HTTP transport for integration with MCP clients (such as Claude Desktop or Gemini clients).
8
+
9
+ ## Key Technologies
10
+
11
+ * **Language:** Ruby
12
+ * **SDK:** `mcp` (Model Context Protocol SDK)
13
+ https://github.com/modelcontextprotocol/ruby-sdk
14
+ * **Database:** Google Cloud Firestore
15
+ * **Server:** Puma (via Rack)
16
+
17
+ ## Project Structure
18
+
19
+ * `main.rb`: Main entry point (Ruby). Registers tools, initializes Firestore, and starts the HTTP transport using Puma.
20
+ * `Makefile`: Development shortcuts (test, lint, clean).
21
+ * `spec/`: Contains test files.
22
+
23
+ ## Ruby MCP Best Practices
24
+
25
+ * **Logging:** Always log to `stderr` (e.g., `LOGGER = Logger.new($stderr)`).
26
+ * **Tool Definition:**
27
+ * Inherit from `MCP::Tool`.
28
+ * Define `description` and `input_schema`.
29
+ * Implement the logic in a class method `self.call`.
30
+ * Return an `MCP::Tool::Response` containing an array of content blocks (e.g., `{ type: 'text', text: '...' }`).
31
+ * **Modularity:** For larger projects, keep tools in separate files. In this project, they are currently in `main.rb` for simplicity.
32
+ * **Error Handling:** Wrap tool logic in `begin...rescue` blocks or check pre-requisites (like database connectivity) to return meaningful error messages to the client.
33
+ * **Environment Variables:** Use `dotenv` for local development. Ensure sensitive credentials are never committed.
34
+
35
+ ## Firestore Integration
36
+
37
+ * **Client:** Uses the `google-cloud-firestore` gem.
38
+ * **Collection:** The primary collection used is `inventory`.
39
+ * **Schema (Inventory):**
40
+ * `name` (String)
41
+ * `price` (Number)
42
+ * `quantity` (Number)
43
+ * `imgfile` (String)
44
+ * `timestamp` (Timestamp)
45
+ * `actualdateadded` (Timestamp)
46
+ * **Operations:**
47
+ * `seed`: Populates the database with sample data.
48
+ * `reset`: Clears the `inventory` collection.
49
+ * `get_products`: Retrieves all items.
50
+ * `get_product_by_id`: Retrieves a specific item by document ID.
51
+ * `get_root`: Returns a welcome message.
52
+ * `check_db`: Checks database connectivity.
53
+
54
+ ## Development Setup
55
+
56
+ 1. **Install Dependencies:**
57
+ ```bash
58
+ bundle install
59
+ ```
60
+ 2. **Environment Variables:** Create a `.env` file with necessary Google Cloud credentials if not using default application credentials.
61
+
62
+ ## Running the Server
63
+
64
+ The server is configured to run using a streaming HTTP transport on port 8080.
65
+
66
+ ```bash
67
+ bundle exec ruby main.rb
68
+ ```
69
+
70
+ *Note: Since this is an MCP server, it is typically spawned or connected to by an MCP client.*
71
+
72
+ ## Ruby MCP Developer Resources
73
+
74
+ * **MCP Ruby SDK (GitHub):** [https://github.com/modelcontextprotocol/ruby-sdk](https://github.com/modelcontextprotocol/ruby-sdk)
75
+ * **Model Context Protocol Documentation:** [https://modelcontextprotocol.io/](https://modelcontextprotocol.io/)
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Firestore Inventory MCP Server (Ruby)
2
+
3
+ A Ruby implementation of a **Model Context Protocol (MCP)** server that connects to **Google Cloud Firestore**. This server exposes tools to manage and inspect a "Cymbal Superstore" inventory database over a streaming HTTP transport.
4
+
5
+ It is designed to be used with MCP clients (like Claude Desktop or Gemini Code Assist) to enable LLMs to interact with your Firestore data.
6
+
7
+ ## Features & Tools
8
+
9
+ This server provides the following MCP tools:
10
+
11
+ * **`get_root`**: Returns a welcome message and confirms the server is reachable.
12
+ * **`check_db`**: Checks the connectivity status of the Firestore database.
13
+ * **`get_products`**: Retrieves the full list of products from the inventory.
14
+ * **`get_product_by_id`**: Fetches details for a specific product using its document ID.
15
+ * **`seed`**: Populates the Firestore `inventory` collection with sample data (useful for demos/testing).
16
+ * **`reset`**: Clears all documents from the `inventory` collection.
17
+
18
+ ## Prerequisites
19
+
20
+ * **Ruby 3.0+**
21
+ * **Google Cloud Project**: You need a Google Cloud project with Firestore enabled.
22
+ * **Authentication**: The environment where this server runs must be authenticated with Google Cloud.
23
+ * Locally, you can use `gcloud auth application-default login`.
24
+ * Or set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of your service account key JSON file.
25
+
26
+ ## Setup
27
+
28
+ 1. **Clone the repository**:
29
+ ```bash
30
+ git clone <your-repo-url>
31
+ cd firestore-https-ruby
32
+ ```
33
+
34
+ 2. **Install Dependencies**:
35
+ ```bash
36
+ bundle install
37
+ ```
38
+
39
+ 3. **Configure Environment**:
40
+ Create a `.env` file if you need to load specific environment variables (handled by `dotenv`).
41
+
42
+ ## Running the Server
43
+
44
+ This server communicates over **HTTP** using Server-Sent Events (SSE). It is not meant to be run manually in a terminal for human interaction, but rather spawned or connected to by an MCP client.
45
+
46
+ To start the server:
47
+
48
+ ```bash
49
+ bundle exec ruby main.rb
50
+ ```
51
+
52
+ The server will start on port 8080 (by default).
53
+
54
+ ### Integration with MCP Clients
55
+
56
+ Configure your MCP client to connect to the server's HTTP endpoint or run it as a command if the client supports it. For example:
57
+
58
+ **Command:** `bundle`
59
+ **Args:** `['exec', 'ruby', '/path/to/firestore-https-ruby/main.rb']`
60
+
61
+ ## Development
62
+
63
+ ### Testing
64
+
65
+ Run the test suite using RSpec:
66
+
67
+ ```bash
68
+ bundle exec rspec
69
+ ```
70
+
71
+ ### Linting
72
+
73
+ Check code style with RuboCop:
74
+
75
+ ```bash
76
+ bundle exec rubocop
77
+ ```
78
+
79
+ ### Building the Gem
80
+
81
+ This project can also be built as a Ruby gem:
82
+
83
+ ```bash
84
+ gem build firestore-mcp-server.gemspec
85
+ ```
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'time'
5
+ require 'json'
6
+ require 'google/cloud/firestore'
7
+
8
+ module MCPServer
9
+ # Configuration and initialization for the MCP server.
10
+ module Config
11
+ LOGGER = Logger.new($stderr)
12
+ LOGGER.level = Logger::INFO
13
+ LOGGER.formatter = proc do |severity, datetime, _progname, msg|
14
+ log_entry = {
15
+ timestamp: datetime.iso8601,
16
+ level: severity
17
+ }
18
+ if msg.is_a?(Hash)
19
+ log_entry.merge!(msg)
20
+ else
21
+ log_entry[:message] = msg.to_s
22
+ end
23
+ "#{log_entry.to_json}\n"
24
+ end
25
+
26
+ def self.logger
27
+ LOGGER
28
+ end
29
+
30
+ def self.firestore
31
+ @firestore
32
+ end
33
+
34
+ def self.db_running?
35
+ @db_running
36
+ end
37
+
38
+ def self.init_firestore
39
+ @firestore = Google::Cloud::Firestore.new
40
+ @db_running = true
41
+ logger.info 'Firestore client initialized'
42
+ rescue StandardError => e
43
+ logger.error "Failed to initialize Firestore: #{e.message}"
44
+ @db_running = false
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'config'
4
+
5
+ module MCPServer
6
+ # Helper class for database operations.
7
+ class DatabaseHelper
8
+ def self.doc_to_product(doc)
9
+ data = doc.data
10
+ {
11
+ id: doc.document_id,
12
+ name: data[:name],
13
+ price: data[:price],
14
+ quantity: data[:quantity],
15
+ imgfile: data[:imgfile],
16
+ timestamp: data[:timestamp],
17
+ actualdateadded: data[:actualdateadded]
18
+ }
19
+ end
20
+
21
+ def self.add_or_update_firestore(product)
22
+ firestore = MCPServer::Config.firestore
23
+ query = firestore.col('inventory').where('name', '==', product[:name]).get
24
+
25
+ if query.empty?
26
+ firestore.col('inventory').add(product)
27
+ else
28
+ query.each do |doc|
29
+ doc.ref.update(product)
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.seed_database
35
+ seed_old_products
36
+ seed_recent_products
37
+ seed_out_of_stock_products
38
+ end
39
+
40
+ # rubocop:disable Metrics/MethodLength
41
+ def self.seed_old_products
42
+ names = [
43
+ 'Apples', 'Bananas', 'Milk', 'Whole Wheat Bread', 'Eggs', 'Cheddar Cheese',
44
+ 'Whole Chicken', 'Rice', 'Black Beans', 'Bottled Water', 'Apple Juice',
45
+ 'Cola', 'Coffee Beans', 'Green Tea', 'Watermelon', 'Broccoli',
46
+ 'Jasmine Rice', 'Yogurt', 'Beef', 'Shrimp', 'Walnuts',
47
+ 'Sunflower Seeds', 'Fresh Basil', 'Cinnamon'
48
+ ]
49
+
50
+ names.each do |name|
51
+ product = {
52
+ name: name,
53
+ price: rand(1..10),
54
+ quantity: rand(1..500),
55
+ imgfile: "product-images/#{name.gsub(/\s+/, '').downcase}.png",
56
+ timestamp: Time.now - rand(0..31_536_000) - 7_776_000,
57
+ actualdateadded: Time.now
58
+ }
59
+ MCPServer::Config.logger.info "⬆️ Adding (or updating) product in firestore: #{product[:name]}"
60
+ add_or_update_firestore(product)
61
+ end
62
+ end
63
+
64
+ def self.seed_recent_products
65
+ names = [
66
+ 'Parmesan Crisps', 'Pineapple Kombucha', 'Maple Almond Butter',
67
+ 'Mint Chocolate Cookies', 'White Chocolate Caramel Corn', 'Acai Smoothie Packs',
68
+ 'Smores Cereal', 'Peanut Butter and Jelly Cups'
69
+ ]
70
+
71
+ names.each do |name|
72
+ product = {
73
+ name: name,
74
+ price: rand(1..10),
75
+ quantity: rand(1..100),
76
+ imgfile: "product-images/#{name.gsub(/\s+/, '').downcase}.png",
77
+ timestamp: Time.now - rand(0..518_400),
78
+ actualdateadded: Time.now
79
+ }
80
+ MCPServer::Config.logger.info "🆕 Adding (or updating) product in firestore: #{product[:name]}"
81
+ add_or_update_firestore(product)
82
+ end
83
+ end
84
+
85
+ def self.seed_out_of_stock_products
86
+ names = ['Wasabi Party Mix', 'Jalapeno Seasoning']
87
+
88
+ names.each do |name|
89
+ product = {
90
+ name: name,
91
+ price: rand(1..10),
92
+ quantity: 0,
93
+ imgfile: "product-images/#{name.gsub(/\s+/, '').downcase}.png",
94
+ timestamp: Time.now - rand(0..518_400),
95
+ actualdateadded: Time.now
96
+ }
97
+ MCPServer::Config.logger.info "😱 Adding (or updating) out of stock product in firestore: #{product[:name]}"
98
+ add_or_update_firestore(product)
99
+ end
100
+ end
101
+ # rubocop:enable Metrics/MethodLength
102
+
103
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
104
+ def self.clean_firestore_collection
105
+ MCPServer::Config.logger.info 'Cleaning Firestore collection...'
106
+ firestore = MCPServer::Config.firestore
107
+ snapshot = firestore.col('inventory').get
108
+ return if snapshot.empty?
109
+
110
+ batch = firestore.batch
111
+ snapshot.each_with_index do |doc, index|
112
+ batch.delete(doc.ref)
113
+ if ((index + 1) % 400).zero?
114
+ batch.commit
115
+ batch = firestore.batch
116
+ end
117
+ end
118
+ batch.commit if (snapshot.size % 400).positive?
119
+ MCPServer::Config.logger.info 'Firestore collection cleaned.'
120
+ end
121
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
122
+ end
123
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mcp'
4
+ require_relative '../config'
5
+
6
+ module MCPServer
7
+ module Tools
8
+ # Tool to check if the database is running.
9
+ class CheckDb < MCP::Tool
10
+ description 'Checks if the inventory database is running.'
11
+ input_schema(type: 'object', properties: {})
12
+
13
+ def self.call(*)
14
+ MCP::Tool::Response.new(
15
+ [{ type: 'text', text: "Database running: #{MCPServer::Config.db_running?}" }]
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mcp'
4
+ require 'json'
5
+ require_relative '../config'
6
+ require_relative '../database_helper'
7
+
8
+ module MCPServer
9
+ module Tools
10
+ # Tool to retrieve a specific product by its ID.
11
+ class GetProductById < MCP::Tool
12
+ description 'Get a single product from the inventory database by its ID'
13
+ input_schema(
14
+ type: 'object',
15
+ properties: {
16
+ id: { type: 'string', description: 'The ID of the product to get' }
17
+ },
18
+ required: ['id']
19
+ )
20
+
21
+ def self.call(id:)
22
+ unless MCPServer::Config.db_running?
23
+ return MCP::Tool::Response.new([{ type: 'text', text: 'Database not running.' }], is_error: true)
24
+ end
25
+
26
+ doc = MCPServer::Config.firestore.col('inventory').doc(id).get
27
+ unless doc.exists?
28
+ return MCP::Tool::Response.new([{ type: 'text', text: 'Product not found.' }], is_error: true)
29
+ end
30
+
31
+ product = MCPServer::DatabaseHelper.doc_to_product(doc)
32
+ MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(product) }])
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mcp'
4
+ require 'json'
5
+ require_relative '../config'
6
+ require_relative '../database_helper'
7
+
8
+ module MCPServer
9
+ module Tools
10
+ # Tool to retrieve all products from the inventory.
11
+ class GetProducts < MCP::Tool
12
+ description 'Get a list of all products from the inventory database'
13
+ input_schema(type: 'object', properties: {})
14
+
15
+ def self.call(*)
16
+ unless MCPServer::Config.db_running?
17
+ return MCP::Tool::Response.new([{ type: 'text', text: 'Inventory database is not running.' }], is_error: true)
18
+ end
19
+
20
+ firestore = MCPServer::Config.firestore
21
+ products = firestore.col('inventory').get.map { |doc| MCPServer::DatabaseHelper.doc_to_product(doc) }
22
+ MCP::Tool::Response.new(
23
+ [{ type: 'text', text: JSON.pretty_generate(products) }]
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mcp'
4
+
5
+ module MCPServer
6
+ module Tools
7
+ # Tool to get the root greeting.
8
+ class GetRoot < MCP::Tool
9
+ description 'Get a greeting from the Cymbal Superstore Inventory API.'
10
+ input_schema(type: 'object', properties: {})
11
+
12
+ def self.call(*)
13
+ MCP::Tool::Response.new(
14
+ [{ type: 'text', text: '🍎 Hello! This is the Cymbal Superstore Inventory API.' }]
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mcp'
4
+ require_relative '../config'
5
+ require_relative '../database_helper'
6
+
7
+ module MCPServer
8
+ module Tools
9
+ # Tool to reset the inventory database.
10
+ class Reset < MCP::Tool
11
+ description 'Clears all products from the inventory database.'
12
+ input_schema(type: 'object', properties: {})
13
+
14
+ def self.call(*)
15
+ unless MCPServer::Config.db_running?
16
+ return MCP::Tool::Response.new([{ type: 'text', text: 'Inventory database is not running.' }], is_error: true)
17
+ end
18
+
19
+ MCPServer::DatabaseHelper.clean_firestore_collection
20
+ MCP::Tool::Response.new(
21
+ [{ type: 'text', text: 'Database reset successfully.' }]
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mcp'
4
+ require_relative '../config'
5
+ require_relative '../database_helper'
6
+
7
+ module MCPServer
8
+ module Tools
9
+ # Tool to seed the inventory database.
10
+ class Seed < MCP::Tool
11
+ description 'Seed the inventory database with products.'
12
+ input_schema(type: 'object', properties: {})
13
+
14
+ def self.call(*)
15
+ unless MCPServer::Config.db_running?
16
+ return MCP::Tool::Response.new([{ type: 'text', text: 'Inventory database is not running.' }], is_error: true)
17
+ end
18
+
19
+ MCPServer::DatabaseHelper.seed_database
20
+ MCP::Tool::Response.new(
21
+ [{ type: 'text', text: 'Database seeded successfully.' }]
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
data/main.rb ADDED
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Redirect stdout to stderr to ensure all output goes to stderr immediately
4
+ $stdout.reopen($stderr)
5
+
6
+ require 'mcp'
7
+ require 'rack'
8
+ require 'rackup'
9
+ require 'json'
10
+ require 'puma'
11
+ require 'dotenv/load'
12
+
13
+ require_relative 'lib/mcp_server/config'
14
+ require_relative 'lib/mcp_server/database_helper'
15
+ require_relative 'lib/mcp_server/tools/get_products'
16
+ require_relative 'lib/mcp_server/tools/get_product_by_id'
17
+ require_relative 'lib/mcp_server/tools/seed'
18
+ require_relative 'lib/mcp_server/tools/reset'
19
+ require_relative 'lib/mcp_server/tools/get_root'
20
+ require_relative 'lib/mcp_server/tools/check_db'
21
+
22
+ # Initialize Configuration and Firestore
23
+ MCPServer::Config.init_firestore
24
+ LOGGER = MCPServer::Config.logger
25
+
26
+ # Configure MCP
27
+ MCP.configure do |config|
28
+ config.protocol_version = '2024-11-05'
29
+ end
30
+
31
+ # Custom transport to fix response format for SSE
32
+ class FixedStreamableHTTPTransport < MCP::Server::Transports::StreamableHTTPTransport
33
+ private
34
+
35
+ def send_response_to_stream(stream, response, _session_id)
36
+ message = JSON.parse(response)
37
+ send_to_stream(stream, message)
38
+ [202, {}, []]
39
+ end
40
+ end
41
+
42
+ # Middleware for JSON request logging
43
+ class JsonRequestLogger
44
+ def initialize(app, logger)
45
+ @app = app
46
+ @logger = logger
47
+ end
48
+
49
+ def call(env)
50
+ status, headers, body = @app.call(env)
51
+ @logger.info(
52
+ type: 'request',
53
+ method: env['REQUEST_METHOD'],
54
+ path: env['PATH_INFO'],
55
+ status: status,
56
+ remote_addr: env['REMOTE_ADDR']
57
+ )
58
+ [status, headers, body]
59
+ end
60
+ end
61
+
62
+ # Initialize MCP Server
63
+ server = MCP::Server.new(
64
+ name: 'inventory-server',
65
+ version: '1.0.0',
66
+ tools: [
67
+ MCPServer::Tools::GetProducts,
68
+ MCPServer::Tools::GetProductById,
69
+ MCPServer::Tools::Seed,
70
+ MCPServer::Tools::Reset,
71
+ MCPServer::Tools::GetRoot,
72
+ MCPServer::Tools::CheckDb
73
+ ]
74
+ )
75
+
76
+ # Create the Fixed Streamable HTTP transport
77
+ transport = FixedStreamableHTTPTransport.new(server)
78
+ server.transport = transport
79
+
80
+ # Create the Rack application
81
+ base_app = proc do |env|
82
+ request = Rack::Request.new(env)
83
+ transport.handle_request(request)
84
+ end
85
+
86
+ # Wrap with JSON logger
87
+ app = JsonRequestLogger.new(base_app, LOGGER)
88
+
89
+ # Run the server using streaming HTTP transport
90
+ if __FILE__ == $PROGRAM_NAME
91
+ begin
92
+ port = ENV.fetch('PORT', 8080).to_i
93
+ LOGGER.info "Starting MCP server: #{server.name} (v#{server.version}) on HTTP port #{port}"
94
+ Rackup::Handler.get('puma').run(app, Port: port, Host: '0.0.0.0', Quiet: true)
95
+ rescue Interrupt
96
+ LOGGER.info 'Shutting down MCP server...'
97
+ transport.close
98
+ rescue StandardError => e
99
+ LOGGER.error(message: "Server error: #{e.message}", backtrace: e.backtrace)
100
+ exit 1
101
+ end
102
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: firestore-https-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - xbill
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: dotenv
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: logger
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.7'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.7'
40
+ description: Exposes Firestore operations (inventory management) as MCP tools over
41
+ stdio.
42
+ email:
43
+ - xbill9@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - GEMINI.md
49
+ - README.md
50
+ - lib/mcp_server/config.rb
51
+ - lib/mcp_server/database_helper.rb
52
+ - lib/mcp_server/tools/check_db.rb
53
+ - lib/mcp_server/tools/get_product_by_id.rb
54
+ - lib/mcp_server/tools/get_products.rb
55
+ - lib/mcp_server/tools/get_root.rb
56
+ - lib/mcp_server/tools/reset.rb
57
+ - lib/mcp_server/tools/seed.rb
58
+ - main.rb
59
+ homepage: https://github.com/xbill9/gemini-cli-codeassist/firestore-https-ruby
60
+ licenses:
61
+ - MIT
62
+ metadata:
63
+ homepage_uri: https://github.com/xbill9/gemini-cli-codeassist/firestore-https-ruby
64
+ source_code_uri: https://github.com/xbill9/gemini-cli-codeassist/firestore-https-ruby
65
+ bug_tracker_uri: https://github.com/xbill9/gemini-cli-codeassist/firestore-https-ruby/issues
66
+ rubygems_mfa_required: 'true'
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 3.1.0
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubygems_version: 3.6.9
82
+ specification_version: 4
83
+ summary: A Model Context Protocol (MCP) server for Google Cloud Firestore.
84
+ test_files: []