mcpsmith 0.2.0__tar.gz → 0.2.1__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.
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/.claude-plugin/plugin.json +2 -2
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/PKG-INFO +2 -1
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/pyproject.toml +2 -1
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/server.json +2 -2
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/__init__.py +1 -1
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/importers/__init__.py +2 -1
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/runtime/http.py +11 -1
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_runtime.py +9 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/uv.lock +3 -1
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/.claude-plugin/marketplace.json +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/.github/workflows/ci.yml +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/.github/workflows/publish.yml +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/.gitignore +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/AGENTS.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/LICENSE +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/README.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/docs/design.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/docs/superpowers/plans/2026-10-21-hub-core.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/docs/superpowers/specs/2026-10-20-mcp-everything-design.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/skills/build-mcp-server/SKILL.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/skills/design-mcp-tools/SKILL.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/skills/extract-api/SKILL.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/browser.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/capture.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/check.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/cli.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/codegen.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/design/__init__.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/design/_digest.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/design/_draft.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/design/_validate.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/design/guide.md +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/design/llm.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/hub.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/importers/har.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/importers/openapi.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/importers/rea.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/model.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/record.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/runtime/__init__.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/runtime/interpret.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/runtime/server.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/runtime/shape.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/runtime/transforms.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/secrets.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/server.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/templates/ci.yml +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/templates/conftest.py.tmpl +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/templates/gitignore +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/src/mcpsmith/templates/publish.yml +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/conftest.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/fake_cdp.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/fixtures/har/shop.har +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/fixtures/openapi/petstore2.yaml +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/fixtures/openapi/petstore3.json +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/fixtures/openapi/tasks31.json +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/fixtures/rea/scenario.json +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_browser.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_cli.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_codegen.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_design.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_hub.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_importers.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_interpret.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_record.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_secrets.py +0 -0
- {mcpsmith-0.2.0 → mcpsmith-0.2.1}/tests/test_transforms.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpsmith",
|
|
3
3
|
"displayName": "mcpsmith",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Turn an OpenAPI file or a recorded website session into a curated, tested MCP server. Skills and an MCP server for your coding agent.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sepehr Radmard",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"mcpsmith": {
|
|
24
24
|
"command": "uvx",
|
|
25
25
|
"args": [
|
|
26
|
-
"mcpsmith@0.2.
|
|
26
|
+
"mcpsmith@0.2.1",
|
|
27
27
|
"mcp"
|
|
28
28
|
]
|
|
29
29
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mcpsmith
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Turn an OpenAPI file or a recorded website session into a curated, tested MCP server, with an LLM designing the tools.
|
|
5
5
|
Project-URL: Homepage, https://github.com/sepehr071/mcpsmith
|
|
6
6
|
Project-URL: Issues, https://github.com/sepehr071/mcpsmith/issues
|
|
@@ -22,6 +22,7 @@ Requires-Dist: httpx>=0.27
|
|
|
22
22
|
Requires-Dist: keyring>=25
|
|
23
23
|
Requires-Dist: mcp<3,>=2.2
|
|
24
24
|
Requires-Dist: pyyaml>=6
|
|
25
|
+
Requires-Dist: truststore>=0.9
|
|
25
26
|
Requires-Dist: tzdata>=2024.1; sys_platform == 'win32'
|
|
26
27
|
Requires-Dist: websockets>=12
|
|
27
28
|
Provides-Extra: capture
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mcpsmith"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Turn an OpenAPI file or a recorded website session into a curated, tested MCP server, with an LLM designing the tools."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -22,6 +22,7 @@ classifiers = [
|
|
|
22
22
|
dependencies = [
|
|
23
23
|
"mcp>=2.2,<3",
|
|
24
24
|
"httpx>=0.27",
|
|
25
|
+
"truststore>=0.9",
|
|
25
26
|
"pyyaml>=6",
|
|
26
27
|
"websockets>=12",
|
|
27
28
|
"keyring>=25",
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
10
|
"websiteUrl": "https://github.com/sepehr071/mcpsmith",
|
|
11
|
-
"version": "0.2.
|
|
11
|
+
"version": "0.2.1",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "pypi",
|
|
15
15
|
"registryBaseUrl": "https://pypi.org",
|
|
16
16
|
"identifier": "mcpsmith",
|
|
17
|
-
"version": "0.2.
|
|
17
|
+
"version": "0.2.1",
|
|
18
18
|
"runtimeHint": "uvx",
|
|
19
19
|
"transport": {
|
|
20
20
|
"type": "stdio"
|
|
@@ -10,13 +10,14 @@ import yaml
|
|
|
10
10
|
|
|
11
11
|
from mcpsmith.importers import har, openapi, rea
|
|
12
12
|
from mcpsmith.model import Source
|
|
13
|
+
from mcpsmith.runtime.http import tls_context
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def load(path_or_url: str, hosts: list[str] | None = None) -> Source:
|
|
16
17
|
"""`hosts` filters HAR traffic to those hosts (exact or subdomain); ignored for OpenAPI."""
|
|
17
18
|
origin = None
|
|
18
19
|
if path_or_url.startswith(("http://", "https://")):
|
|
19
|
-
resp = httpx.get(path_or_url, follow_redirects=True, timeout=60)
|
|
20
|
+
resp = httpx.get(path_or_url, follow_redirects=True, timeout=60, verify=tls_context())
|
|
20
21
|
resp.raise_for_status()
|
|
21
22
|
text, origin = resp.text, str(resp.url)
|
|
22
23
|
else:
|
|
@@ -16,12 +16,14 @@ import logging
|
|
|
16
16
|
import os
|
|
17
17
|
import random
|
|
18
18
|
import re
|
|
19
|
+
import ssl
|
|
19
20
|
import time
|
|
20
21
|
from collections.abc import Awaitable, Callable
|
|
21
22
|
from typing import Any
|
|
22
23
|
from urllib.parse import quote
|
|
23
24
|
|
|
24
25
|
import httpx
|
|
26
|
+
import truststore
|
|
25
27
|
from mcp.server.mcpserver.exceptions import ToolError
|
|
26
28
|
|
|
27
29
|
log = logging.getLogger("mcpsmith")
|
|
@@ -38,6 +40,12 @@ class ApiError(ToolError):
|
|
|
38
40
|
self.status = status
|
|
39
41
|
|
|
40
42
|
|
|
43
|
+
@functools.cache
|
|
44
|
+
def tls_context() -> ssl.SSLContext:
|
|
45
|
+
"""Verify with the OS trust store (fixes incomplete chains, honors corporate CAs); verification stays on."""
|
|
46
|
+
return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
47
|
+
|
|
48
|
+
|
|
41
49
|
@functools.cache
|
|
42
50
|
def _curl() -> tuple[type, Any] | None:
|
|
43
51
|
"""The curl_cffi transport class (Chrome TLS/HTTP2 fingerprint) and CurlOpt, or None without the extra."""
|
|
@@ -283,7 +291,9 @@ class Api:
|
|
|
283
291
|
proxy=proxy,
|
|
284
292
|
max_connections=2 * self.concurrency,
|
|
285
293
|
)
|
|
286
|
-
return httpx.AsyncHTTPTransport(
|
|
294
|
+
return httpx.AsyncHTTPTransport(
|
|
295
|
+
verify=tls_context(), proxy=proxy, limits=httpx.Limits(max_connections=2 * self.concurrency)
|
|
296
|
+
)
|
|
287
297
|
|
|
288
298
|
async def _request(self, method, url, query, headers, payload, host) -> tuple[httpx.Response, bytes]:
|
|
289
299
|
client, limit = self._get_client()
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import ssl
|
|
2
3
|
from typing import Annotated
|
|
3
4
|
|
|
4
5
|
import httpx
|
|
5
6
|
import pytest
|
|
7
|
+
import truststore
|
|
6
8
|
from mcp import Client
|
|
7
9
|
from pydantic import Field
|
|
8
10
|
|
|
@@ -351,3 +353,10 @@ async def test_browser_auth_cookie_errors_map_to_not_running(exc):
|
|
|
351
353
|
api = make_api(lambda r: httpx.Response(200, json={}), auth={"type": "browser"}, cookie_provider=down)
|
|
352
354
|
with pytest.raises(ApiError, match="The mcpsmith Chrome is not running"):
|
|
353
355
|
await api.call("GET", "/x")
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def test_plain_transport_verifies_with_os_trust_store():
|
|
359
|
+
transport = Api(base_url="https://api.example.com", env_prefix="EX_MCP")._make_transport(None)
|
|
360
|
+
ctx = transport._pool._ssl_context
|
|
361
|
+
assert isinstance(ctx, truststore.SSLContext) and ctx is http.tls_context()
|
|
362
|
+
assert ctx.verify_mode == ssl.CERT_REQUIRED
|
|
@@ -689,13 +689,14 @@ wheels = [
|
|
|
689
689
|
|
|
690
690
|
[[package]]
|
|
691
691
|
name = "mcpsmith"
|
|
692
|
-
version = "0.2.
|
|
692
|
+
version = "0.2.1"
|
|
693
693
|
source = { editable = "." }
|
|
694
694
|
dependencies = [
|
|
695
695
|
{ name = "httpx" },
|
|
696
696
|
{ name = "keyring" },
|
|
697
697
|
{ name = "mcp" },
|
|
698
698
|
{ name = "pyyaml" },
|
|
699
|
+
{ name = "truststore" },
|
|
699
700
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
700
701
|
{ name = "websockets", version = "16.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
701
702
|
{ name = "websockets", version = "17.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
@@ -726,6 +727,7 @@ requires-dist = [
|
|
|
726
727
|
{ name = "mcp", specifier = ">=2.2,<3" },
|
|
727
728
|
{ name = "playwright", marker = "extra == 'capture'", specifier = ">=1.45" },
|
|
728
729
|
{ name = "pyyaml", specifier = ">=6" },
|
|
730
|
+
{ name = "truststore", specifier = ">=0.9" },
|
|
729
731
|
{ name = "tzdata", marker = "sys_platform == 'win32'", specifier = ">=2024.1" },
|
|
730
732
|
{ name = "websockets", specifier = ">=12" },
|
|
731
733
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcpsmith-0.2.0 → mcpsmith-0.2.1}/docs/superpowers/specs/2026-10-20-mcp-everything-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|