plasma-mcp 0.0.1

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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +16 -0
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +26 -0
  5. data/LICENSE +21 -0
  6. data/README.md +207 -0
  7. data/Rakefile +16 -0
  8. data/docs/ROADMAP.md +46 -0
  9. data/exe/plasma +8 -0
  10. data/lib/plasma/application.rb +193 -0
  11. data/lib/plasma/auth.rb +82 -0
  12. data/lib/plasma/auth_server.rb +45 -0
  13. data/lib/plasma/cli.rb +93 -0
  14. data/lib/plasma/component_generator.rb +111 -0
  15. data/lib/plasma/generator.rb +132 -0
  16. data/lib/plasma/loader.rb +32 -0
  17. data/lib/plasma/prompt.rb +10 -0
  18. data/lib/plasma/resource.rb +39 -0
  19. data/lib/plasma/server.rb +47 -0
  20. data/lib/plasma/storage/application_record.rb +10 -0
  21. data/lib/plasma/storage/record.rb +16 -0
  22. data/lib/plasma/storage/variable.rb +53 -0
  23. data/lib/plasma/storage.rb +101 -0
  24. data/lib/plasma/templates/.dockerignore.erb +40 -0
  25. data/lib/plasma/templates/.env.erb +2 -0
  26. data/lib/plasma/templates/.github/workflows/docker-build.yml.erb +52 -0
  27. data/lib/plasma/templates/.gitignore.erb +40 -0
  28. data/lib/plasma/templates/.ruby-version.erb +1 -0
  29. data/lib/plasma/templates/Dockerfile.erb +18 -0
  30. data/lib/plasma/templates/Gemfile.erb +6 -0
  31. data/lib/plasma/templates/README.md.erb +228 -0
  32. data/lib/plasma/templates/app/prompts/example_prompt.rb.erb +30 -0
  33. data/lib/plasma/templates/app/resources/example_resource.rb.erb +36 -0
  34. data/lib/plasma/templates/app/tools/example_tool.rb.erb +35 -0
  35. data/lib/plasma/templates/app/variables/example_variable.erb +20 -0
  36. data/lib/plasma/templates/config/application.rb.erb +24 -0
  37. data/lib/plasma/templates/config/boot.rb.erb +12 -0
  38. data/lib/plasma/templates/config/initializers/example.rb.erb +7 -0
  39. data/lib/plasma/templates/lib/version.rb.erb +5 -0
  40. data/lib/plasma/tool.rb +131 -0
  41. data/lib/plasma/version.rb +5 -0
  42. data/lib/plasma.rb +19 -0
  43. data/sig/plasma.rbs +4 -0
  44. metadata +257 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: acc716872cb9b5f8f874e0b29c1f9e26a5cec5ec82c8a527a5cb1c1a3d1d3ab8
4
+ data.tar.gz: aab888a1298721434f6f89faa11540c06417cba3d2e4adb349f828defff87bf0
5
+ SHA512:
6
+ metadata.gz: 96d837ef33358f0896cc23262823688dd6bc83c92626d434185a32c5084af411848bf3ba63fff3d94c9b11a535af153520879858e882b956c42dfe8117e9a1a9
7
+ data.tar.gz: a13232228c0136175ce1efa6051b965590a8d6a91901bf6a1615493d04a80536426b74831940e5a4c37c70c4ec7ab75f09665d9a5e869b2bcfa5fda6724f1e21
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ plugins:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.4
7
+ NewCops: enable
8
+
9
+ Style/StringLiterals:
10
+ EnforcedStyle: double_quotes
11
+
12
+ Style/StringLiteralsInInterpolation:
13
+ EnforcedStyle: double_quotes
14
+
15
+ Layout/TrailingEmptyLines:
16
+ EnforcedStyle: final_newline
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.3
data/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - Initial release
12
+
13
+ ### Changed
14
+ - None
15
+
16
+ ### Deprecated
17
+ - None
18
+
19
+ ### Removed
20
+ - None
21
+
22
+ ### Fixed
23
+ - None
24
+
25
+ ### Security
26
+ - None
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Jacob Foster Heimark
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Plasma
2
+
3
+ [![Join our Discord](https://img.shields.io/discord/1338362937550573643?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/B6NPUAgYmH)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![CI](https://github.com/plasma-mcp/plasma/actions/workflows/main.yml/badge.svg)](https://github.com/plasma-mcp/plasma/actions/workflows/main.yml)
6
+
7
+ The **P**ractical **L**aunchpad **A**ssisting with **M**CP **A**bstraction.
8
+
9
+ ![Plasma Logo](assets/ruby-plasma-mcp-300x300.png)
10
+
11
+ Plasma is a Ruby-based SDK that provides a Rails-inspired, convention-over-configuration approach to building Model Context Protocol servers. Like a plasma engine powering a spacecraft, Plasma provides the fundamental infrastructure to power your MCP services with minimal resistance.
12
+
13
+ > [🚀 Getting Started](#getting-started) • [📖 Usage Guide](#usage-guide) • [⚙️ Development](#development)
14
+
15
+ > ⚠️ **Warning**: Plasma is currently in pre-alpha development (0.0.1-pre). Until version 0.1.0 is released, all versions (including patch updates) may contain breaking changes. This allows us to rapidly iterate and improve the API based on early feedback. See our [roadmap](docs/ROADMAP.md) for more details.
16
+
17
+ ## Features
18
+
19
+ - ✅ Rails-inspired project and component generation (tools, prompts, and resources)
20
+ - ✅ Storage system for persistent data (variables and records)
21
+ - 🚧 Local authentication system via Omniauth (coming soon - partially implemented)
22
+
23
+ ## Getting Started
24
+
25
+ ### Requirements
26
+
27
+ - Ruby `3.4` or higher (tested on `3.4.2+`)
28
+ - Bundler
29
+ - Docker (optional, for containerized deployment)
30
+
31
+ ### Installation
32
+
33
+ Install Plasma:
34
+
35
+ ```bash
36
+ gem install plasma-mcp
37
+ ```
38
+
39
+ ### Quick Start
40
+
41
+ 1. Create a new project:
42
+ ```bash
43
+ plasma new my_server
44
+ cd my_server
45
+ ```
46
+
47
+ 2. Generate your first tool:
48
+ ```bash
49
+ plasma g tool greeting name:string
50
+ ```
51
+
52
+
53
+ 4. Start your plasma server (in STDIN/STDOUT mode)
54
+ ```bash
55
+ plasma server
56
+ ```
57
+
58
+ 5. Pass it some JSON to try it out:
59
+ ```json
60
+ {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"greeting","arguments":{"name":"Jean-Luc Picard"}}}
61
+ ```
62
+
63
+ You will get the output:
64
+ ```json
65
+ {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"Hello from GreetingTool with params: Jean-Luc Picard "}],"isError":false}}
66
+ ```
67
+
68
+ Congratulations. We have liftoff! 🚀
69
+
70
+ ## Usage Guide
71
+
72
+ ### Project Structure
73
+ ```
74
+ my_server/
75
+ ├── app/
76
+ │ ├── prompts/ # MCP prompts
77
+ │ ├── resources/ # MCP resources
78
+ │ ├── tools/ # MCP tools
79
+ │ ├── variables/ # Per-sesion variables (e.g. `current_user_email_variable`)
80
+ │ └── records/ # Stored objects (e.g. `task_records`)
81
+ ├── config/
82
+ │ ├── initializers/ # Preload configuration
83
+ │ ├── application.rb # MCP server configuration
84
+ │ └── boot.rb # Launch ignition sequence
85
+ └── .env # Environment variables
86
+ ```
87
+
88
+ ### Creating Tools
89
+
90
+ Generate a new tool using the CLI:
91
+
92
+ ```bash
93
+ plasma g tool greeting name:string
94
+ ```
95
+
96
+ This will generate a tool file in `app/tools/greeting_tool.rb` that follows this structure:
97
+
98
+ ```ruby
99
+ # app/tools/greeting_tool.rb
100
+ module MyServer
101
+ module Tools
102
+ # A friendly space station greeting system
103
+ class GreetingTool < Plasma::Tool
104
+ param :name,
105
+ type: :string,
106
+ description: "Name of the space traveler to welcome"
107
+
108
+ def call
109
+ respond_with(:text,
110
+ text: <<~GREETING
111
+ Welcome aboard, #{params[:name]}!
112
+ Your presence has been registered in our stellar database. 🚀
113
+ GREETING
114
+ )
115
+ end
116
+ end
117
+ end
118
+ end
119
+ ```
120
+
121
+ The tool's description is automatically extracted from the comment above the class. Parameters are defined using the `param` class method, which supports:
122
+ - `type`: The parameter type (`:string`, `:number`, `:float`, `:boolean`, or `:array`)
123
+ - `description`: A description of the parameter
124
+ - `required`: Whether the parameter is required (defaults to false)
125
+
126
+ Parameters are accessed in the `call` method via the `params` hash.
127
+
128
+ The `respond_with` method supports several response types: `:text`, `:image`, `:resource` and `:error`
129
+
130
+ ### Configuration
131
+
132
+ Configure your application in `config/application.rb`:
133
+
134
+ ```ruby
135
+ module MyServer
136
+ class Application < Plasma::Application
137
+ self.initialize! do |config|
138
+ config.name = "My Custom Server Name"
139
+ end
140
+ end
141
+ ```
142
+
143
+ ## Deployment
144
+
145
+ ### Traditional `STDIN/STDOUT` Deployment
146
+
147
+ 1. Set up your environment variables
148
+ 2. Run the server:
149
+ ```bash
150
+ plasma server
151
+ ```
152
+
153
+ ### Docker `STDIN/STDOUT` Deployment (coming soon)
154
+
155
+ Docker deployment support is currently under development. This feature will provide:
156
+ - Pre-built Docker images for easy deployment
157
+ - Containerized environment for consistent execution
158
+ - Integration with popular container orchestration platforms
159
+
160
+ Stay tuned for updates in our upcoming releases!
161
+
162
+ ### SSE Deployment (coming soon)
163
+
164
+ Server-Sent Events (SSE) deployment is planned for version 0.2.0. This feature will include:
165
+ - Real-time event streaming capabilities
166
+ - WebSocket support for bidirectional communication
167
+ - Enhanced monitoring and debugging tools
168
+ - Improved error handling and recovery mechanisms
169
+
170
+ Stay tuned for updates in our upcoming releases!
171
+
172
+ ## Development
173
+
174
+ ### Getting Started with Development
175
+
176
+ After git cloning, run `bin/setup` to install dependencies. Then, run `rake test` to run the diagnostics. You can also run `bin/console` for a low level command terminal.
177
+
178
+ To start an interactive console for your project (similar to `rails console`):
179
+
180
+ ```bash
181
+ plasma console
182
+ ```
183
+
184
+ This will give you access to your project's environment where you can interact with your components, storage variables, and other features:
185
+
186
+ ```ruby
187
+ # Example console session
188
+ > MyTool.new.call
189
+ => "Tool execution result"
190
+ ```
191
+
192
+ ### Roadmap
193
+ For detailed information about our development status, versioning strategy, and roadmap, please see [ROADMAP.md](docs/ROADMAP.md).
194
+
195
+ ## Community & Contributing
196
+
197
+ Join our Discord community to connect with other developers, get help, and stay updated on the latest developments:
198
+
199
+ [![Join our Discord](https://img.shields.io/discord/1338362937550573643?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/B6NPUAgYmH)
200
+
201
+ ## Contributing
202
+
203
+ Improvements and bug reports are welcome on GitHub at https://github.com/plasma-mcp/plasma
204
+
205
+ ## License
206
+
207
+ This project is available as open source under the terms of the MIT License.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_globs = ["test/test_helper.rb", "test/**/*_test.rb"]
10
+ end
11
+
12
+ require "rubocop/rake_task"
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
data/docs/ROADMAP.md ADDED
@@ -0,0 +1,46 @@
1
+ # Plasma Development Roadmap
2
+
3
+ ## Versioning Strategy
4
+
5
+ **Until version 0.1.0 is released, all versions (including patch updates) may contain breaking changes.** This allows us to rapidly iterate and improve the API based on early feedback. After version 0.1.0, we will strictly follow semantic versioning:
6
+
7
+ - **Major version** (1.0.0, 2.0.0): Breaking changes
8
+ - **Minor version** (1.1.0, 1.2.0): New features, no breaking changes
9
+ - **Patch version** (1.0.1, 1.0.2): Bug fixes and minor improvements, no breaking changes
10
+
11
+ ## Current Status
12
+
13
+ Plasma is currently in alpha development (0.0.x). The project is actively being developed with the following planned milestones:
14
+
15
+ - Version 0.0.1: Initial alpha release with basic functionality
16
+ - Version 0.1.0: Beta release with core features
17
+ - Version 0.2.0: First stable release
18
+
19
+ ## Development Focus
20
+
21
+ ### 0.1 Development Focus
22
+
23
+ - [x] Storage system for persistent data
24
+ - [x] Component generation for prompts, resources, and tools
25
+ - [x] Improved tool response mechanics (i.e. `respond_with`-ish rails pattern on response)
26
+ - [x] Improved tool ergonomics with type hints and Ruby magic
27
+ - [x] Draft authentication system implementation
28
+ - [x] Docker file template as part of new generation (and commands to upload)
29
+ - [x] Including docker usage in readme
30
+ - [x] First pass at authentication system with Sinatra
31
+ - [ ] Reference servers with example usage
32
+ - [ ] Gem & executable as part of new generation
33
+ - [ ] CLI command to get json for Claude (docker and gem versions)
34
+
35
+ ### 0.2 Development Focus
36
+ - Complete authentication system implementation
37
+ - Update to include features from latest MCP version (`2025-03-27`)
38
+ - Server-Sent Events (SSE) support for real-time updates
39
+ - Enhanced OAuth integration with latest MCP authentication patterns
40
+ - Improved error handling and recovery mechanisms
41
+ - Performance optimizations for high-concurrency scenarios
42
+ - Generate rspec tests and test framework on `plasma new`
43
+ - Migrate to rspec for plasma-mcp itself
44
+ - Expand test coverage and CI/CD pipeline improvements
45
+ - Testing framework improvements with helper methods and fixtures for common MCP patterns
46
+ - Wiki / improved documentation
data/exe/plasma ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
+
6
+ require "plasma"
7
+
8
+ Plasma::CLI.start(ARGV)
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/introspection"
4
+ require "active_support/core_ext/class/subclasses"
5
+ require "model_context_protocol"
6
+ require "zeitwerk"
7
+ require "sinatra/base"
8
+ require "omniauth"
9
+ require "securerandom"
10
+
11
+ module Plasma
12
+ # Base application class for PLASMA applications
13
+ class Application
14
+ class << self
15
+ attr_accessor :config, :registry, :server
16
+
17
+ # Initialize the application
18
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
19
+ def initialize!
20
+ # Set up configuration
21
+ @config ||= Configuration.new
22
+ yield @config if block_given?
23
+
24
+ # Set default name based on module name if not explicitly set
25
+ if @config.name.nil?
26
+ module_name = to_s.split("::").first
27
+ @config.name = "#{module_name} MCP Server"
28
+ end
29
+
30
+ # Set up autoloading
31
+ module_name = module_parent.name
32
+ loader = Zeitwerk::Loader.new
33
+ loader.push_dir("./app", namespace: Object.const_get(module_name))
34
+ loader.push_dir(File.expand_path("../plasma", __dir__), namespace: Plasma)
35
+ loader.setup
36
+
37
+ # Load prompts, resources, and tools
38
+ load_all_components
39
+
40
+ # Load the plasma auth server in case it is subclassed
41
+ require "plasma/auth_server"
42
+
43
+ # Create the server
44
+ @server = ModelContextProtocol::Server.new do |config|
45
+ config.name = @config.name || "PLASMA MCP Server"
46
+ config.version = @config.version || "1.0.0"
47
+ config.enable_log = @config.enable_log
48
+
49
+ # Apply environment variables
50
+ @config.required_env_vars.each do |var|
51
+ config.require_environment_variable(var)
52
+ end
53
+
54
+ @config.env_vars.each do |key, value|
55
+ config.set_environment_variable(key, value)
56
+ end
57
+ end
58
+
59
+ # Set up the registry
60
+ setup_registry
61
+ end
62
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
63
+
64
+ # Start the MCP server
65
+ def start_server
66
+ @server.start
67
+ end
68
+
69
+ # Load all the application's components
70
+ def load_all_components
71
+ load_prompts
72
+ load_resources
73
+ load_tools
74
+ load_variables
75
+ load_records
76
+ end
77
+
78
+ # Find all prompt classes
79
+ def prompts
80
+ descendants_of("Prompts")
81
+ end
82
+
83
+ # Find all resource classes
84
+ def resources
85
+ descendants_of("Resources")
86
+ end
87
+
88
+ # Find all tool classes
89
+ def tools
90
+ descendants_of("Tools")
91
+ end
92
+
93
+ private
94
+
95
+ # Set up the MCP registry with all components
96
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
97
+ def setup_registry
98
+ @registry = ModelContextProtocol::Server::Registry.new do
99
+ prompts list_changed: true do
100
+ Plasma::Prompt.descendants.each do |prompt_class|
101
+ register prompt_class
102
+ end
103
+ end
104
+
105
+ resources list_changed: true, subscribe: true do
106
+ Plasma::Resource.descendants.each do |resource_class|
107
+ register resource_class
108
+ end
109
+ end
110
+
111
+ tools list_changed: true do
112
+ Plasma::Tool.descendants.each do |tool_class|
113
+ register tool_class
114
+ end
115
+ end
116
+ end
117
+
118
+ # Set the registry on the server
119
+ @server.configuration.registry = registry
120
+ end
121
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
122
+
123
+ # Find all descendants of a particular module
124
+ def descendants_of(module_name)
125
+ # Get the application module
126
+ app_module = to_s.split("::").first.constantize
127
+
128
+ # Find all classes that are defined in the specified module
129
+ ObjectSpace.each_object(Class).select do |klass|
130
+ klass.name&.start_with?("#{app_module}::#{module_name}::") &&
131
+ klass != app_module.const_get(module_name)
132
+ end
133
+ end
134
+
135
+ # Load all prompt files
136
+ def load_prompts
137
+ Dir[File.join(app_root, "app/prompts/**/*.rb")].each { |f| require f }
138
+ end
139
+
140
+ # Load all resource files
141
+ def load_resources
142
+ Dir[File.join(app_root, "app/resources/**/*.rb")].each { |f| require f }
143
+ end
144
+
145
+ # Load all tool files
146
+ def load_tools
147
+ Dir[File.join(app_root, "app/tools/**/*.rb")].each { |f| require f }
148
+ end
149
+
150
+ # Load all variable files
151
+ def load_variables
152
+ Dir[File.join(app_root, "app/variables/**/*.rb")].each { |f| require f }
153
+ end
154
+
155
+ # Load all record files
156
+ def load_records
157
+ Dir[File.join(app_root, "app/records/**/*.rb")].each { |f| require f }
158
+ end
159
+
160
+ # Get the application root directory
161
+ def app_root
162
+ # Default to the current directory
163
+ Dir.pwd
164
+ end
165
+ end
166
+
167
+ # Configuration class for PLASMA applications
168
+ class Configuration
169
+ attr_accessor :name, :version, :enable_log, :module_name, :auth_port, :auth_host, :omniauth_provider_args
170
+ attr_reader :required_env_vars, :env_vars
171
+
172
+ def initialize
173
+ @name = nil
174
+ @version = nil
175
+ @enable_log = true
176
+ @module_name = nil
177
+ @required_env_vars = []
178
+ @env_vars = {}
179
+ @auth_port = 4567
180
+ @auth_host = "localhost"
181
+ @omniauth_provider_args = {}
182
+ end
183
+
184
+ def require_environment_variable(name)
185
+ @required_env_vars << name
186
+ end
187
+
188
+ def set_environment_variable(name, value)
189
+ @env_vars[name] = value
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "puma"
4
+
5
+ module Plasma
6
+ # Handles authentication operations
7
+ class Auth
8
+ attr_reader :options
9
+
10
+ def initialize(options = {})
11
+ @options = options
12
+ end
13
+
14
+ def start
15
+ puts "Starting authentication server..."
16
+
17
+ return error_not_plasma_project unless plasma_project?
18
+
19
+ application = Plasma::Loader.load_project
20
+ config = application.config
21
+
22
+ port, host = resolve_port_and_host(config)
23
+ auth_server_class = resolve_auth_server_class(application)
24
+ puma_auth_server = Puma::Server.new(auth_server_class.new)
25
+ puma_auth_server.add_tcp_listener(host, port)
26
+
27
+ run_and_wait_for_shutdown(puma_auth_server, auth_server_class)
28
+
29
+ # TODO: check if the config vars have actually been set
30
+ puts "Authentication server succesfully shutdown."
31
+ end
32
+
33
+ private
34
+
35
+ def error_not_plasma_project
36
+ puts "Error: Not a PLASMA project directory. Please run this command from the root of a PLASMA project."
37
+ false
38
+ end
39
+
40
+ def resolve_port_and_host(config)
41
+ [
42
+ @options[:port] || config.auth_port || 4567,
43
+ @options[:host] || config.auth_host || "localhost"
44
+ ]
45
+ end
46
+
47
+ def resolve_auth_server_class(application)
48
+ application.module_parent.const_get("AuthServer")
49
+ end
50
+
51
+ def run_and_wait_for_shutdown(puma_auth_server, auth_server_class)
52
+ puma_auth_server.run
53
+ Timeout.timeout(300) do
54
+ sleep 0.1 until auth_server_class.ready_to_shutdown?
55
+ rescue Timeout::Error
56
+ puts "Authentication server did not shutdown in time. Forcing shutdown."
57
+ end
58
+ puma_auth_server.halt
59
+ end
60
+
61
+ def plasma_project?
62
+ File.exist?("config/application.rb") &&
63
+ File.exist?("config/boot.rb") &&
64
+ Dir.exist?("app/prompts") &&
65
+ Dir.exist?("app/resources") &&
66
+ Dir.exist?("app/tools")
67
+ end
68
+
69
+ def start_auth_server
70
+ puts "Starting authentication server on #{options[:host]}:#{options[:port]}..."
71
+ puts "This is a placeholder for the actual authentication server."
72
+ puts "In a real implementation, this would start a server with OAuth endpoints."
73
+
74
+ # This is a placeholder for the actual authentication server implementation
75
+ loop do
76
+ sleep 1
77
+ end
78
+ rescue Interrupt
79
+ puts "\nShutting down authentication server..."
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "omniauth"
4
+ require "sinatra/base"
5
+ require "rack/protection"
6
+
7
+ module Plasma
8
+ # Handles OAuth authentication for PLASMA applications
9
+ class AuthServer < Sinatra::Base
10
+ use Rack::Session::Cookie, secret: ENV.fetch("SESSION_SECRET") { SecureRandom.hex(32) }
11
+ use Rack::Protection::AuthenticityToken
12
+
13
+ app = Plasma::Loader.load_project
14
+
15
+ use OmniAuth::Builder do
16
+ provider(*app.config.omniauth_provider_args)
17
+ end
18
+
19
+ def self.mark_ready_to_shutdown
20
+ @ready_to_shutdown = true
21
+ end
22
+
23
+ def self.ready_to_shutdown?
24
+ @ready_to_shutdown ||= false
25
+ end
26
+
27
+ get "/" do
28
+ raise NotImplementedError, "This endpoint is not implemented, you must implement it in your auth_server.rb"
29
+ end
30
+
31
+ configure :development do
32
+ set :show_exceptions, true
33
+ end
34
+
35
+ get "/callback" do
36
+ token = request.env.dig("omniauth.auth", :credentials, :token)
37
+ if token
38
+ self.class.mark_ready_to_shutdown
39
+ "token: #{token}"
40
+ else
41
+ "No token found, request.env: #{request.env.inspect}"
42
+ end
43
+ end
44
+ end
45
+ end