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.
- checksums.yaml +7 -0
- data/.rubocop.yml +16 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +26 -0
- data/LICENSE +21 -0
- data/README.md +207 -0
- data/Rakefile +16 -0
- data/docs/ROADMAP.md +46 -0
- data/exe/plasma +8 -0
- data/lib/plasma/application.rb +193 -0
- data/lib/plasma/auth.rb +82 -0
- data/lib/plasma/auth_server.rb +45 -0
- data/lib/plasma/cli.rb +93 -0
- data/lib/plasma/component_generator.rb +111 -0
- data/lib/plasma/generator.rb +132 -0
- data/lib/plasma/loader.rb +32 -0
- data/lib/plasma/prompt.rb +10 -0
- data/lib/plasma/resource.rb +39 -0
- data/lib/plasma/server.rb +47 -0
- data/lib/plasma/storage/application_record.rb +10 -0
- data/lib/plasma/storage/record.rb +16 -0
- data/lib/plasma/storage/variable.rb +53 -0
- data/lib/plasma/storage.rb +101 -0
- data/lib/plasma/templates/.dockerignore.erb +40 -0
- data/lib/plasma/templates/.env.erb +2 -0
- data/lib/plasma/templates/.github/workflows/docker-build.yml.erb +52 -0
- data/lib/plasma/templates/.gitignore.erb +40 -0
- data/lib/plasma/templates/.ruby-version.erb +1 -0
- data/lib/plasma/templates/Dockerfile.erb +18 -0
- data/lib/plasma/templates/Gemfile.erb +6 -0
- data/lib/plasma/templates/README.md.erb +228 -0
- data/lib/plasma/templates/app/prompts/example_prompt.rb.erb +30 -0
- data/lib/plasma/templates/app/resources/example_resource.rb.erb +36 -0
- data/lib/plasma/templates/app/tools/example_tool.rb.erb +35 -0
- data/lib/plasma/templates/app/variables/example_variable.erb +20 -0
- data/lib/plasma/templates/config/application.rb.erb +24 -0
- data/lib/plasma/templates/config/boot.rb.erb +12 -0
- data/lib/plasma/templates/config/initializers/example.rb.erb +7 -0
- data/lib/plasma/templates/lib/version.rb.erb +5 -0
- data/lib/plasma/tool.rb +131 -0
- data/lib/plasma/version.rb +5 -0
- data/lib/plasma.rb +19 -0
- data/sig/plasma.rbs +4 -0
- 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
|
+
[](https://discord.gg/B6NPUAgYmH)
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
5
|
+
[](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
|
+

|
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
|
+
[](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,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
|
data/lib/plasma/auth.rb
ADDED
@@ -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
|