airbrake_mcp 1.0.2 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2240a66c5be534864e153cecb78600f027a30e877974cbad9a21a1b6b4823bf
4
- data.tar.gz: d55ff5ccc6a5e9e4bb4bcb943582c997faec795378affc05175f6bd4c47f57b3
3
+ metadata.gz: 7ed4e827382daeb7329a9b383855ae55ab2c26e337585c753d80aaddeebf5179
4
+ data.tar.gz: 4b96efeffd6206d6cee8f5459f32e8a61cdba1b2ba03985a2b1767c51ef6c689
5
5
  SHA512:
6
- metadata.gz: 6190373dabc25f17f30f5d7ecade25fe344802a72f5ff70085e05b652bd2f2adab074fdd8503bbde1a9de41f961a609cd13f9e6fdaeeddcc1b414c6a63519317
7
- data.tar.gz: 346e2155248f9e9449f879542071be018b68e624db4fdb5771696fe6de12353193d88439ede288fb71476a32341d2a46773a8de21b7b34312673118d03b4b184
6
+ metadata.gz: 21e39e8a19ba4f93d450cb6029cc42075ae270ed86bedae141ca59bd62c7ca34aa7ab4e051e2d86a19e7f0342440a4e389481657aa733ff49ae8e789a12e0775
7
+ data.tar.gz: 795083e21d0151602d6bbefc6a28c3b33659594370497e574e3c2f8c66721312d069c4824828ebf4c63c863ac05532793ccb8ac277020b8c42c4f20a019d2899
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.4] - 2026-01-06
4
+
5
+ ### Fixed
6
+ - Fixed API URL path construction (removed leading slashes causing requests to bypass /api/v4 path)
7
+ - Fixed MCP response serialization (workaround for MCP gem bug where Content objects aren't converted to hashes)
8
+
9
+ ## [1.0.3] - 2026-01-06
10
+
11
+ ### Fixed
12
+ - Removed `require 'bundler/setup'` from bin script to fix Bundler conflicts when running from project directories with their own Gemfile
13
+ - Made dotenv loading optional (development dependency only)
14
+
15
+ ### Changed
16
+ - Simplified README installation instructions
17
+
3
18
  ## [1.0.2] - 2025-01-06
4
19
 
5
20
  ### Added
data/README.md CHANGED
@@ -48,41 +48,36 @@ bundle install
48
48
  ### Quick Setup
49
49
 
50
50
  ```bash
51
- claude mcp add airbrake $(which airbrake_mcp) \
51
+ claude mcp add airbrake airbrake_mcp \
52
52
  -e AIRBRAKE_USER_KEY=your_user_key \
53
53
  -e AIRBRAKE_PROJECT_ID=123456
54
54
  ```
55
55
 
56
56
  ### Using rbenv/asdf/chruby
57
57
 
58
- If you use a Ruby version manager, Claude Code runs in a non-interactive shell without access to your `.bashrc`/`.zshrc`. You need to provide the full path to the shim:
58
+ If you use a Ruby version manager, Claude Code runs in a non-interactive shell without access to your shell profile. Provide the full path to the shim:
59
59
 
60
60
  ```bash
61
- # For rbenv
61
+ # rbenv
62
62
  claude mcp add airbrake ~/.rbenv/shims/airbrake_mcp \
63
63
  -e AIRBRAKE_USER_KEY=your_user_key \
64
64
  -e AIRBRAKE_PROJECT_ID=123456
65
65
 
66
- # For asdf
66
+ # asdf
67
67
  claude mcp add airbrake ~/.asdf/shims/airbrake_mcp \
68
68
  -e AIRBRAKE_USER_KEY=your_user_key \
69
69
  -e AIRBRAKE_PROJECT_ID=123456
70
-
71
- # For chruby (use full gem path)
72
- claude mcp add airbrake $(gem environment gemdir)/bin/airbrake_mcp \
73
- -e AIRBRAKE_USER_KEY=your_user_key \
74
- -e AIRBRAKE_PROJECT_ID=123456
75
70
  ```
76
71
 
77
72
  ### Manual Configuration
78
73
 
79
- Add to `~/.claude/settings.json` or project's `.claude/settings.local.json`:
74
+ Add to `~/.claude/settings.json`:
80
75
 
81
76
  ```json
82
77
  {
83
78
  "mcpServers": {
84
79
  "airbrake": {
85
- "command": "/full/path/to/airbrake_mcp",
80
+ "command": "airbrake_mcp",
86
81
  "args": [],
87
82
  "env": {
88
83
  "AIRBRAKE_USER_KEY": "your_user_key",
data/bin/airbrake_mcp CHANGED
@@ -1,8 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'bundler/setup'
5
- require 'dotenv/load'
4
+ # Load dotenv for development (optional)
5
+ begin
6
+ require 'dotenv/load'
7
+ rescue LoadError
8
+ # dotenv is optional, used only for local development
9
+ end
6
10
 
7
11
  require 'airbrake_mcp'
8
12
 
@@ -15,36 +15,36 @@ module AirbrakeMcp
15
15
  attr_reader :project_id
16
16
 
17
17
  def projects
18
- get('/projects')['projects']
18
+ get('projects')['projects']
19
19
  end
20
20
 
21
21
  def groups(project_id: @project_id, page: 1, limit: 20)
22
- get("/projects/#{project_id}/groups", { page: page, limit: limit })
22
+ get("projects/#{project_id}/groups", { page: page, limit: limit })
23
23
  end
24
24
 
25
25
  def group(group_id, project_id: @project_id)
26
- get("/projects/#{project_id}/groups/#{group_id}")
26
+ get("projects/#{project_id}/groups/#{group_id}")
27
27
  end
28
28
 
29
29
  def notices(group_id, project_id: @project_id, page: 1, limit: 10)
30
- get("/projects/#{project_id}/groups/#{group_id}/notices", { page: page, limit: limit })
30
+ get("projects/#{project_id}/groups/#{group_id}/notices", { page: page, limit: limit })
31
31
  end
32
32
 
33
33
  # Write operations
34
34
  def resolve_group(group_id, project_id: @project_id)
35
- put("/projects/#{project_id}/groups/#{group_id}/resolved")
35
+ put("projects/#{project_id}/groups/#{group_id}/resolved")
36
36
  end
37
37
 
38
38
  def unresolve_group(group_id, project_id: @project_id)
39
- put("/projects/#{project_id}/groups/#{group_id}/unresolved")
39
+ put("projects/#{project_id}/groups/#{group_id}/unresolved")
40
40
  end
41
41
 
42
42
  def mute_group(group_id, project_id: @project_id)
43
- put("/projects/#{project_id}/groups/#{group_id}/muted")
43
+ put("projects/#{project_id}/groups/#{group_id}/muted")
44
44
  end
45
45
 
46
46
  def unmute_group(group_id, project_id: @project_id)
47
- put("/projects/#{project_id}/groups/#{group_id}/unmuted")
47
+ put("projects/#{project_id}/groups/#{group_id}/unmuted")
48
48
  end
49
49
 
50
50
  private
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AirbrakeMcp
4
+ module ResponseHelper
5
+ # Workaround for MCP gem bug where Content objects aren't converted to hashes
6
+ # in Response#to_h. This creates responses with pre-converted content.
7
+ def self.text_response(text, error: false)
8
+ MCP::Tool::Response.new([{ type: "text", text: text }], error: error)
9
+ end
10
+ end
11
+ end
@@ -19,24 +19,16 @@ module AirbrakeMcp
19
19
  pid = project_id || client.project_id
20
20
 
21
21
  unless pid
22
- return MCP::Tool::Response.new([
23
- MCP::Content::Text.new("Error: No project_id specified and no default configured")
24
- ], error: true)
22
+ return ResponseHelper.text_response("Error: No project_id specified and no default configured", error: true)
25
23
  end
26
24
 
27
25
  group = client.group(group_id, project_id: pid)
28
26
 
29
- MCP::Tool::Response.new([
30
- MCP::Content::Text.new(Formatters.format_group_detail(group))
31
- ])
27
+ ResponseHelper.text_response(Formatters.format_group_detail(group))
32
28
  rescue Client::NotFoundError
33
- MCP::Tool::Response.new([
34
- MCP::Content::Text.new("Error: Error group #{group_id} not found")
35
- ], error: true)
29
+ ResponseHelper.text_response("Error: Error group #{group_id} not found", error: true)
36
30
  rescue Client::ApiError => e
37
- MCP::Tool::Response.new([
38
- MCP::Content::Text.new("Error: #{e.message}")
39
- ], error: true)
31
+ ResponseHelper.text_response("Error: #{e.message}", error: true)
40
32
  end
41
33
  end
42
34
  end
@@ -21,9 +21,7 @@ module AirbrakeMcp
21
21
  pid = project_id || client.project_id
22
22
 
23
23
  unless pid
24
- return MCP::Tool::Response.new([
25
- MCP::Content::Text.new("Error: No project_id specified and no default configured")
26
- ], error: true)
24
+ return ResponseHelper.text_response("Error: No project_id specified and no default configured", error: true)
27
25
  end
28
26
 
29
27
  result = client.groups(project_id: pid, page: page, limit: limit)
@@ -33,13 +31,9 @@ module AirbrakeMcp
33
31
  result['groups'] = result['groups'].select { |g| g['resolved'] == resolved }
34
32
  end
35
33
 
36
- MCP::Tool::Response.new([
37
- MCP::Content::Text.new(Formatters.format_groups(result))
38
- ])
34
+ ResponseHelper.text_response(Formatters.format_groups(result))
39
35
  rescue Client::ApiError => e
40
- MCP::Tool::Response.new([
41
- MCP::Content::Text.new("Error: #{e.message}")
42
- ], error: true)
36
+ ResponseHelper.text_response("Error: #{e.message}", error: true)
43
37
  end
44
38
  end
45
39
  end
@@ -21,24 +21,16 @@ module AirbrakeMcp
21
21
  pid = project_id || client.project_id
22
22
 
23
23
  unless pid
24
- return MCP::Tool::Response.new([
25
- MCP::Content::Text.new("Error: No project_id specified and no default configured")
26
- ], error: true)
24
+ return ResponseHelper.text_response("Error: No project_id specified and no default configured", error: true)
27
25
  end
28
26
 
29
27
  result = client.notices(group_id, project_id: pid, page: page, limit: limit)
30
28
 
31
- MCP::Tool::Response.new([
32
- MCP::Content::Text.new(Formatters.format_notices(result))
33
- ])
29
+ ResponseHelper.text_response(Formatters.format_notices(result))
34
30
  rescue Client::NotFoundError
35
- MCP::Tool::Response.new([
36
- MCP::Content::Text.new("Error: Error group #{group_id} not found")
37
- ], error: true)
31
+ ResponseHelper.text_response("Error: Error group #{group_id} not found", error: true)
38
32
  rescue Client::ApiError => e
39
- MCP::Tool::Response.new([
40
- MCP::Content::Text.new("Error: #{e.message}")
41
- ], error: true)
33
+ ResponseHelper.text_response("Error: #{e.message}", error: true)
42
34
  end
43
35
  end
44
36
  end
@@ -10,13 +10,9 @@ module AirbrakeMcp
10
10
  client = server_context[:client]
11
11
  projects = client.projects
12
12
 
13
- MCP::Tool::Response.new([
14
- MCP::Content::Text.new(Formatters.format_projects(projects))
15
- ])
13
+ ResponseHelper.text_response(Formatters.format_projects(projects))
16
14
  rescue Client::ApiError => e
17
- MCP::Tool::Response.new([
18
- MCP::Content::Text.new("Error: #{e.message}")
19
- ], error: true)
15
+ ResponseHelper.text_response("Error: #{e.message}", error: true)
20
16
  end
21
17
  end
22
18
  end
@@ -20,9 +20,7 @@ module AirbrakeMcp
20
20
  pid = project_id || client.project_id
21
21
 
22
22
  unless pid
23
- return MCP::Tool::Response.new([
24
- MCP::Content::Text.new("Error: No project_id specified and no default configured")
25
- ], error: true)
23
+ return ResponseHelper.text_response("Error: No project_id specified and no default configured", error: true)
26
24
  end
27
25
 
28
26
  if mute
@@ -33,17 +31,11 @@ module AirbrakeMcp
33
31
  action = "unmuted"
34
32
  end
35
33
 
36
- MCP::Tool::Response.new([
37
- MCP::Content::Text.new("Error group ##{group_id} #{action}")
38
- ])
34
+ ResponseHelper.text_response("Error group ##{group_id} #{action}")
39
35
  rescue Client::NotFoundError
40
- MCP::Tool::Response.new([
41
- MCP::Content::Text.new("Error: Error group #{group_id} not found")
42
- ], error: true)
36
+ ResponseHelper.text_response("Error: Error group #{group_id} not found", error: true)
43
37
  rescue Client::ApiError => e
44
- MCP::Tool::Response.new([
45
- MCP::Content::Text.new("Error: #{e.message}")
46
- ], error: true)
38
+ ResponseHelper.text_response("Error: #{e.message}", error: true)
47
39
  end
48
40
  end
49
41
  end
@@ -20,9 +20,7 @@ module AirbrakeMcp
20
20
  pid = project_id || client.project_id
21
21
 
22
22
  unless pid
23
- return MCP::Tool::Response.new([
24
- MCP::Content::Text.new("Error: No project_id specified and no default configured")
25
- ], error: true)
23
+ return ResponseHelper.text_response("Error: No project_id specified and no default configured", error: true)
26
24
  end
27
25
 
28
26
  if resolved
@@ -33,17 +31,11 @@ module AirbrakeMcp
33
31
  action = "unresolved"
34
32
  end
35
33
 
36
- MCP::Tool::Response.new([
37
- MCP::Content::Text.new("Error group ##{group_id} marked as #{action}")
38
- ])
34
+ ResponseHelper.text_response("Error group ##{group_id} marked as #{action}")
39
35
  rescue Client::NotFoundError
40
- MCP::Tool::Response.new([
41
- MCP::Content::Text.new("Error: Error group #{group_id} not found")
42
- ], error: true)
36
+ ResponseHelper.text_response("Error: Error group #{group_id} not found", error: true)
43
37
  rescue Client::ApiError => e
44
- MCP::Tool::Response.new([
45
- MCP::Content::Text.new("Error: #{e.message}")
46
- ], error: true)
38
+ ResponseHelper.text_response("Error: #{e.message}", error: true)
47
39
  end
48
40
  end
49
41
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AirbrakeMcp
4
- VERSION = '1.0.2'
4
+ VERSION = '1.0.4'
5
5
  end
data/lib/airbrake_mcp.rb CHANGED
@@ -5,6 +5,7 @@ require 'mcp'
5
5
  require_relative 'airbrake_mcp/version'
6
6
  require_relative 'airbrake_mcp/client'
7
7
  require_relative 'airbrake_mcp/formatters'
8
+ require_relative 'airbrake_mcp/response_helper'
8
9
  require_relative 'airbrake_mcp/tools/list_projects'
9
10
  require_relative 'airbrake_mcp/tools/list_errors'
10
11
  require_relative 'airbrake_mcp/tools/get_error'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrake_mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - httplab
@@ -95,6 +95,7 @@ files:
95
95
  - lib/airbrake_mcp.rb
96
96
  - lib/airbrake_mcp/client.rb
97
97
  - lib/airbrake_mcp/formatters.rb
98
+ - lib/airbrake_mcp/response_helper.rb
98
99
  - lib/airbrake_mcp/tools/get_error.rb
99
100
  - lib/airbrake_mcp/tools/list_errors.rb
100
101
  - lib/airbrake_mcp/tools/list_notices.rb