second-opinion-mcp 0.3.1__tar.gz → 0.3.3__tar.gz

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 (19) hide show
  1. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/.gitignore +1 -0
  2. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/PKG-INFO +86 -3
  3. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/README.md +85 -2
  4. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/pyproject.toml +1 -1
  5. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/src/second_opinion_mcp/__init__.py +1 -1
  6. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/src/second_opinion_mcp/server.py +43 -0
  7. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/LICENSE +0 -0
  8. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/src/second_opinion_mcp/__main__.py +0 -0
  9. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/src/second_opinion_mcp/cli.py +0 -0
  10. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/__init__.py +0 -0
  11. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/conftest.py +0 -0
  12. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_configuration.py +0 -0
  13. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_connection_pool.py +0 -0
  14. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_error_isolation.py +0 -0
  15. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_input_validation.py +0 -0
  16. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_keyring_security.py +0 -0
  17. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_path_security.py +0 -0
  18. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_rate_limiting.py +0 -0
  19. {second_opinion_mcp-0.3.1 → second_opinion_mcp-0.3.3}/tests/test_streaming_limits.py +0 -0
@@ -50,3 +50,4 @@ Thumbs.db
50
50
 
51
51
  # Distribution / packaging
52
52
  MANIFEST
53
+ second_opinion.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: second-opinion-mcp
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Multi-model AI analysis for Claude - get second opinions from DeepSeek, Kimi, and OpenRouter
5
5
  Project-URL: Homepage, https://github.com/MarvinFS/second-opinion-mcp
6
6
  Project-URL: Repository, https://github.com/MarvinFS/second-opinion-mcp
@@ -143,6 +143,56 @@ Full workflow: parallel reviews from both models, debate, then synthesis instruc
143
143
  Perform a comprehensive code review of ./myproject using review_synthesis
144
144
  ```
145
145
 
146
+ ## Usage Examples
147
+
148
+ ### Thorough Code Review Workflow
149
+
150
+ For comprehensive code reviews, use this prompt pattern with Claude Code:
151
+
152
+ ```
153
+ MyProject: perform a comprehensive deep parallel code review with deepseek and kimi
154
+ using mcp server second-opinion - save resulting md files to the project folder
155
+ to the docs subfolder in md format.
156
+
157
+ After that perform Consensus debate + arbiter synthesis using same mcp server tools
158
+ with opus 4.5 compiling a final document for the final review.
159
+
160
+ First 2 tasks can be run in parallel.
161
+ ```
162
+
163
+ This triggers parallel code_review calls to DeepSeek and Moonshot, then a consensus debate on findings, and finally Claude synthesizes the final review document.
164
+
165
+ ### Quick Second Opinion
166
+
167
+ ```
168
+ Use second_opinion to review this database schema:
169
+ CREATE TABLE users (
170
+ id SERIAL PRIMARY KEY,
171
+ email VARCHAR(255),
172
+ password VARCHAR(255)
173
+ );
174
+ ```
175
+
176
+ ### Critical Challenge
177
+
178
+ ```
179
+ Use challenge to critique this proposal: "We should use a global singleton for
180
+ database connections because it's simpler"
181
+ ```
182
+
183
+ ### Consensus Debate
184
+
185
+ ```
186
+ Use consensus to debate: "GraphQL vs REST for our internal microservices API"
187
+ ```
188
+
189
+ ### Code Review with Focus Areas
190
+
191
+ ```
192
+ Use code_review on directory="./src" with focus_areas=["security", "error-handling"]
193
+ and save_to="./docs/reviews"
194
+ ```
195
+
146
196
  ## Configuration
147
197
 
148
198
  ### Changing Providers
@@ -179,10 +229,23 @@ To update keys:
179
229
  second-opinion-mcp setup
180
230
  ```
181
231
 
182
- Or manually:
232
+ Or manually set each provider's key:
183
233
 
184
234
  ```bash
185
- python -c "import keyring; keyring.set_password('second-opinion', 'deepseek', 'sk-YOUR_NEW_KEY')"
235
+ # DeepSeek (key starts with sk-)
236
+ python -c "import keyring; keyring.set_password('second-opinion', 'deepseek', 'sk-YOUR_DEEPSEEK_KEY')"
237
+
238
+ # Moonshot/Kimi
239
+ python -c "import keyring; keyring.set_password('second-opinion', 'moonshot', 'YOUR_MOONSHOT_KEY')"
240
+
241
+ # OpenRouter (key starts with sk-or-)
242
+ python -c "import keyring; keyring.set_password('second-opinion', 'openrouter', 'sk-or-YOUR_OPENROUTER_KEY')"
243
+ ```
244
+
245
+ Verify keys are configured:
246
+
247
+ ```bash
248
+ python -c "import keyring; print('deepseek:', bool(keyring.get_password('second-opinion', 'deepseek'))); print('moonshot:', bool(keyring.get_password('second-opinion', 'moonshot'))); print('openrouter:', bool(keyring.get_password('second-opinion', 'openrouter')))"
186
249
  ```
187
250
 
188
251
  ### Claude Desktop Configuration
@@ -279,6 +342,25 @@ Use code_review with focus_areas=["security", "error-handling", "performance"]
279
342
  Use code_review on directory="./src" with save_to="./docs/reviews"
280
343
  ```
281
344
 
345
+ ## Updating
346
+
347
+ The server checks for updates on startup and notifies you if a new version is available.
348
+
349
+ To update manually:
350
+
351
+ ```bash
352
+ pipx upgrade second-opinion-mcp
353
+ ```
354
+
355
+ Or reinstall:
356
+
357
+ ```bash
358
+ pipx uninstall second-opinion-mcp
359
+ pipx install second-opinion-mcp
360
+ ```
361
+
362
+ Your API keys are preserved in the system keyring across updates.
363
+
282
364
  ## Uninstalling
283
365
 
284
366
  ```bash
@@ -291,6 +373,7 @@ pipx uninstall second-opinion-mcp
291
373
  # Optional: remove stored API keys
292
374
  python -c "import keyring; keyring.delete_password('second-opinion', 'deepseek')"
293
375
  python -c "import keyring; keyring.delete_password('second-opinion', 'moonshot')"
376
+ python -c "import keyring; keyring.delete_password('second-opinion', 'openrouter')"
294
377
  ```
295
378
 
296
379
  ## Security
@@ -105,6 +105,56 @@ Full workflow: parallel reviews from both models, debate, then synthesis instruc
105
105
  Perform a comprehensive code review of ./myproject using review_synthesis
106
106
  ```
107
107
 
108
+ ## Usage Examples
109
+
110
+ ### Thorough Code Review Workflow
111
+
112
+ For comprehensive code reviews, use this prompt pattern with Claude Code:
113
+
114
+ ```
115
+ MyProject: perform a comprehensive deep parallel code review with deepseek and kimi
116
+ using mcp server second-opinion - save resulting md files to the project folder
117
+ to the docs subfolder in md format.
118
+
119
+ After that perform Consensus debate + arbiter synthesis using same mcp server tools
120
+ with opus 4.5 compiling a final document for the final review.
121
+
122
+ First 2 tasks can be run in parallel.
123
+ ```
124
+
125
+ This triggers parallel code_review calls to DeepSeek and Moonshot, then a consensus debate on findings, and finally Claude synthesizes the final review document.
126
+
127
+ ### Quick Second Opinion
128
+
129
+ ```
130
+ Use second_opinion to review this database schema:
131
+ CREATE TABLE users (
132
+ id SERIAL PRIMARY KEY,
133
+ email VARCHAR(255),
134
+ password VARCHAR(255)
135
+ );
136
+ ```
137
+
138
+ ### Critical Challenge
139
+
140
+ ```
141
+ Use challenge to critique this proposal: "We should use a global singleton for
142
+ database connections because it's simpler"
143
+ ```
144
+
145
+ ### Consensus Debate
146
+
147
+ ```
148
+ Use consensus to debate: "GraphQL vs REST for our internal microservices API"
149
+ ```
150
+
151
+ ### Code Review with Focus Areas
152
+
153
+ ```
154
+ Use code_review on directory="./src" with focus_areas=["security", "error-handling"]
155
+ and save_to="./docs/reviews"
156
+ ```
157
+
108
158
  ## Configuration
109
159
 
110
160
  ### Changing Providers
@@ -141,10 +191,23 @@ To update keys:
141
191
  second-opinion-mcp setup
142
192
  ```
143
193
 
144
- Or manually:
194
+ Or manually set each provider's key:
145
195
 
146
196
  ```bash
147
- python -c "import keyring; keyring.set_password('second-opinion', 'deepseek', 'sk-YOUR_NEW_KEY')"
197
+ # DeepSeek (key starts with sk-)
198
+ python -c "import keyring; keyring.set_password('second-opinion', 'deepseek', 'sk-YOUR_DEEPSEEK_KEY')"
199
+
200
+ # Moonshot/Kimi
201
+ python -c "import keyring; keyring.set_password('second-opinion', 'moonshot', 'YOUR_MOONSHOT_KEY')"
202
+
203
+ # OpenRouter (key starts with sk-or-)
204
+ python -c "import keyring; keyring.set_password('second-opinion', 'openrouter', 'sk-or-YOUR_OPENROUTER_KEY')"
205
+ ```
206
+
207
+ Verify keys are configured:
208
+
209
+ ```bash
210
+ python -c "import keyring; print('deepseek:', bool(keyring.get_password('second-opinion', 'deepseek'))); print('moonshot:', bool(keyring.get_password('second-opinion', 'moonshot'))); print('openrouter:', bool(keyring.get_password('second-opinion', 'openrouter')))"
148
211
  ```
149
212
 
150
213
  ### Claude Desktop Configuration
@@ -241,6 +304,25 @@ Use code_review with focus_areas=["security", "error-handling", "performance"]
241
304
  Use code_review on directory="./src" with save_to="./docs/reviews"
242
305
  ```
243
306
 
307
+ ## Updating
308
+
309
+ The server checks for updates on startup and notifies you if a new version is available.
310
+
311
+ To update manually:
312
+
313
+ ```bash
314
+ pipx upgrade second-opinion-mcp
315
+ ```
316
+
317
+ Or reinstall:
318
+
319
+ ```bash
320
+ pipx uninstall second-opinion-mcp
321
+ pipx install second-opinion-mcp
322
+ ```
323
+
324
+ Your API keys are preserved in the system keyring across updates.
325
+
244
326
  ## Uninstalling
245
327
 
246
328
  ```bash
@@ -253,6 +335,7 @@ pipx uninstall second-opinion-mcp
253
335
  # Optional: remove stored API keys
254
336
  python -c "import keyring; keyring.delete_password('second-opinion', 'deepseek')"
255
337
  python -c "import keyring; keyring.delete_password('second-opinion', 'moonshot')"
338
+ python -c "import keyring; keyring.delete_password('second-opinion', 'openrouter')"
256
339
  ```
257
340
 
258
341
  ## Security
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "second-opinion-mcp"
3
- version = "0.3.1"
3
+ version = "0.3.3"
4
4
  description = "Multi-model AI analysis for Claude - get second opinions from DeepSeek, Kimi, and OpenRouter"
5
5
  requires-python = ">=3.10"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  """Second Opinion MCP Server - Multi-model AI analysis for Claude."""
2
2
 
3
- __version__ = "0.3.1"
3
+ __version__ = "0.3.3"
4
4
  __author__ = "MarvinFS"
5
5
 
6
6
  from second_opinion_mcp.server import mcp, second_opinion, challenge, code_review, consensus, review_synthesis
@@ -1575,6 +1575,42 @@ def _validate_startup_requirements() -> tuple[bool, str]:
1575
1575
  return True, ""
1576
1576
 
1577
1577
 
1578
+ def _check_for_updates() -> tuple[str | None, str | None]:
1579
+ """Check PyPI for newer version of second-opinion-mcp.
1580
+
1581
+ Returns:
1582
+ (latest_version, current_version) if update available, (None, None) otherwise.
1583
+ """
1584
+ import urllib.request
1585
+ import json
1586
+
1587
+ try:
1588
+ from second_opinion_mcp import __version__ as current_version
1589
+ except ImportError:
1590
+ current_version = "0.0.0"
1591
+
1592
+ try:
1593
+ # Quick timeout to not delay startup
1594
+ url = "https://pypi.org/pypi/second-opinion-mcp/json"
1595
+ req = urllib.request.Request(url, headers={"User-Agent": "second-opinion-mcp"})
1596
+ with urllib.request.urlopen(req, timeout=3) as response:
1597
+ data = json.loads(response.read().decode())
1598
+ latest_version = data.get("info", {}).get("version", "0.0.0")
1599
+
1600
+ # Simple version comparison (works for semver)
1601
+ def parse_version(v: str) -> tuple[int, ...]:
1602
+ return tuple(int(x) for x in v.split(".")[:3] if x.isdigit())
1603
+
1604
+ if parse_version(latest_version) > parse_version(current_version):
1605
+ return latest_version, current_version
1606
+
1607
+ except Exception:
1608
+ # Don't fail startup on update check errors
1609
+ pass
1610
+
1611
+ return None, None
1612
+
1613
+
1578
1614
  def main():
1579
1615
  """Run the MCP server with stdio transport."""
1580
1616
  import sys
@@ -1585,6 +1621,13 @@ def main():
1585
1621
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
1586
1622
  )
1587
1623
 
1624
+ # Check for updates (non-blocking, quick timeout)
1625
+ latest, current = _check_for_updates()
1626
+ if latest:
1627
+ print(f"Update available: {current} -> {latest}", file=sys.stderr)
1628
+ print("Run: pipx upgrade second-opinion-mcp", file=sys.stderr)
1629
+ print(file=sys.stderr)
1630
+
1588
1631
  # Validate minimum requirements
1589
1632
  ok, error = _validate_startup_requirements()
1590
1633
  if not ok: