mcp-openapi-proxy 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.
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/PKG-INFO +53 -3
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/README.md +52 -2
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/server_lowlevel.py +1 -1
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/utils.py +25 -3
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/PKG-INFO +53 -3
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/pyproject.toml +1 -1
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/LICENSE +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/__init__.py +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/handlers.py +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/logging_setup.py +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/openapi.py +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/server_fastmcp.py +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy/types.py +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/SOURCES.txt +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/dependency_links.txt +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/entry_points.txt +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/requires.txt +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/top_level.txt +0 -0
- {mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-openapi-proxy
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: MCP server for exposing OpenAPI specifications as MCP tools.
|
|
5
5
|
Author-email: Matthew Hand <11550632+matthewhand@users.noreply.github.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -31,10 +31,11 @@ Dynamic: license-file
|
|
|
31
31
|
- ✅ **Codex**, **Gemini**, **Qwen**, **Kilocode**, **opencode** — native tool calls over stdio
|
|
32
32
|
- ✅ **Vibe** — native discovery and read calls (writes were CLI-flaky, not a proxy issue)
|
|
33
33
|
- ✅ **Letta** — Cloud (via a remote streamable-HTTP MCP URL) and self-hosted (via stdio)
|
|
34
|
-
- ⚠️ **agy** — could not attach in headless mode; MCP tool enablement is interactive-only in agy (an agy limitation, not the proxy)
|
|
35
34
|
|
|
36
35
|
See the [client matrix](#client-matrix) for attach mechanisms, models, and exact results.
|
|
37
36
|
|
|
37
|
+
> 📄 Full write-up: [**Verification case study**](docs/verification-case-study.md) — what the proxy is, the API + client matrices, and every defect found & fixed.
|
|
38
|
+
|
|
38
39
|
**Prompts and resources are real now — including custom resources.** Both MCP surfaces are functional and tested: the `summarize_spec` / `whimsical_blog` prompts and the `spec_file` resource, plus a new `ADDITIONAL_RESOURCES` env var that serves your *own* use-case documents (e.g. a NetBox naming policy or an Asana project-layout guide) as MCP resources — see `examples/resources/`.
|
|
39
40
|
|
|
40
41
|
**Bug fixes (every one live-verified):**
|
|
@@ -63,7 +64,7 @@ Full environment-variable reference is in [Environment Variables](#environment-v
|
|
|
63
64
|
- [Environment Variables](#environment-variables)
|
|
64
65
|
- [Verified Clients & Live Results (2026-06-12)](#verified-clients--live-results-2026-06-12)
|
|
65
66
|
- [Tips](#tips)
|
|
66
|
-
- [Examples](#examples) — Glama, Fly.io, Render, Slack, GetZep, Virustotal, Notion, Asana, APIs.guru, NetBox, Box, WolframAlpha (collapsed)
|
|
67
|
+
- [Examples](#examples) — Glama, Fly.io, Render, Slack, GetZep, Virustotal, Notion, Asana, APIs.guru, NetBox, Box, WolframAlpha, WordPress (collapsed)
|
|
67
68
|
- [Troubleshooting](#troubleshooting)
|
|
68
69
|
- [License](#license)
|
|
69
70
|
|
|
@@ -868,6 +869,55 @@ You can now use the MCP ecosystem to list and invoke WolframAlpha API tools. For
|
|
|
868
869
|
|
|
869
870
|
</details>
|
|
870
871
|
|
|
872
|
+
<details>
|
|
873
|
+
<summary><b>Letta (self-hosted + Cloud)</b> — agent platform; stdio for self-hosted, authenticated remote HTTP for Cloud</summary>
|
|
874
|
+
|
|
875
|
+
Letta runs agents on a server, so attachment differs by deployment:
|
|
876
|
+
|
|
877
|
+
- **Self-hosted Letta** accepts a **stdio** MCP server via `PUT /v1/tools/mcp/servers` — no network exposure.
|
|
878
|
+
- **Letta Cloud** rejects stdio and needs a **remote streamable-HTTP** MCP URL behind authentication.
|
|
879
|
+
|
|
880
|
+
Both were verified live (an agent autonomously called `get_v1_attributes` from the Glama spec through the proxy). Full setup for both paths, including the supergateway wrapper and the security note for the Cloud endpoint, is in [`examples/letta/README.md`](examples/letta/README.md).
|
|
881
|
+
|
|
882
|
+
</details>
|
|
883
|
+
|
|
884
|
+
<details>
|
|
885
|
+
<summary><b>WordPress Example</b> — publish to a real WordPress blog from any MCP agent</summary>
|
|
886
|
+
|
|
887
|
+
This example turns the WordPress REST API into MCP tools so an agent can **create, read, update, and trash blog posts**. It is the example behind a real-world demonstration: a fleet of agent CLIs published to the live blog at **[matthewhand.mywebcommunity.org](https://matthewhand.mywebcommunity.org/)** through this proxy — see the write-up [*“Turning Any API into Agent Tools”*](https://matthewhand.mywebcommunity.org/2026/06/12/turning-any-api-into-agent-tools-a-real-world-test-of-mcp-openapi-proxy/), itself posted via the proxy.
|
|
888
|
+
|
|
889
|
+
Example config — `examples/wordpress-claude_desktop_config.json`:
|
|
890
|
+
|
|
891
|
+
```json
|
|
892
|
+
{
|
|
893
|
+
"mcpServers": {
|
|
894
|
+
"wordpress": {
|
|
895
|
+
"command": "uvx",
|
|
896
|
+
"args": ["mcp-openapi-proxy"],
|
|
897
|
+
"env": {
|
|
898
|
+
"OPENAPI_SPEC_URL": "https://raw.githubusercontent.com/matthewhand/mcp-openapi-proxy/main/examples/wordpress-openapi.json",
|
|
899
|
+
"SERVER_URL_OVERRIDE": "https://your-site.example.com/wp-json",
|
|
900
|
+
"EXTRA_HEADERS": "Authorization: Basic BASE64_OF_USERNAME_COLON_APPLICATION_PASSWORD",
|
|
901
|
+
"IGNORE_SSL_TOOLS": "false",
|
|
902
|
+
"TOOL_WHITELIST": "/wp/v2/posts"
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
Exposed tools (from the bundled `examples/wordpress-openapi.json`): `get_wp_v2_posts`, `post_wp_v2_posts` (create), `get_wp_v2_posts_by_id`, `post_wp_v2_posts_by_id` (update), and `delete_wp_v2_posts_by_id` (trash) — the full post lifecycle.
|
|
910
|
+
|
|
911
|
+
**Auth — use a WordPress *Application Password*, not your login password.** WordPress REST rejects login passwords for Basic auth. In `wp-admin → Users → (your user) → Application Passwords`, create one, then base64-encode `username:application-password` for the `EXTRA_HEADERS` value:
|
|
912
|
+
|
|
913
|
+
```bash
|
|
914
|
+
printf 'myuser:xxxx xxxx xxxx xxxx xxxx xxxx' | base64 -w0
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
Tips: set `IGNORE_SSL_TOOLS=true` only if your host serves a self-signed/mismatched cert; give each agent its own (revocable) application password; keep `TOOL_WHITELIST=/wp/v2/posts` so the agent can touch only posts.
|
|
918
|
+
|
|
919
|
+
</details>
|
|
920
|
+
|
|
871
921
|
## Troubleshooting
|
|
872
922
|
|
|
873
923
|
### JSON-RPC Testing
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
- ✅ **Codex**, **Gemini**, **Qwen**, **Kilocode**, **opencode** — native tool calls over stdio
|
|
10
10
|
- ✅ **Vibe** — native discovery and read calls (writes were CLI-flaky, not a proxy issue)
|
|
11
11
|
- ✅ **Letta** — Cloud (via a remote streamable-HTTP MCP URL) and self-hosted (via stdio)
|
|
12
|
-
- ⚠️ **agy** — could not attach in headless mode; MCP tool enablement is interactive-only in agy (an agy limitation, not the proxy)
|
|
13
12
|
|
|
14
13
|
See the [client matrix](#client-matrix) for attach mechanisms, models, and exact results.
|
|
15
14
|
|
|
15
|
+
> 📄 Full write-up: [**Verification case study**](docs/verification-case-study.md) — what the proxy is, the API + client matrices, and every defect found & fixed.
|
|
16
|
+
|
|
16
17
|
**Prompts and resources are real now — including custom resources.** Both MCP surfaces are functional and tested: the `summarize_spec` / `whimsical_blog` prompts and the `spec_file` resource, plus a new `ADDITIONAL_RESOURCES` env var that serves your *own* use-case documents (e.g. a NetBox naming policy or an Asana project-layout guide) as MCP resources — see `examples/resources/`.
|
|
17
18
|
|
|
18
19
|
**Bug fixes (every one live-verified):**
|
|
@@ -41,7 +42,7 @@ Full environment-variable reference is in [Environment Variables](#environment-v
|
|
|
41
42
|
- [Environment Variables](#environment-variables)
|
|
42
43
|
- [Verified Clients & Live Results (2026-06-12)](#verified-clients--live-results-2026-06-12)
|
|
43
44
|
- [Tips](#tips)
|
|
44
|
-
- [Examples](#examples) — Glama, Fly.io, Render, Slack, GetZep, Virustotal, Notion, Asana, APIs.guru, NetBox, Box, WolframAlpha (collapsed)
|
|
45
|
+
- [Examples](#examples) — Glama, Fly.io, Render, Slack, GetZep, Virustotal, Notion, Asana, APIs.guru, NetBox, Box, WolframAlpha, WordPress (collapsed)
|
|
45
46
|
- [Troubleshooting](#troubleshooting)
|
|
46
47
|
- [License](#license)
|
|
47
48
|
|
|
@@ -846,6 +847,55 @@ You can now use the MCP ecosystem to list and invoke WolframAlpha API tools. For
|
|
|
846
847
|
|
|
847
848
|
</details>
|
|
848
849
|
|
|
850
|
+
<details>
|
|
851
|
+
<summary><b>Letta (self-hosted + Cloud)</b> — agent platform; stdio for self-hosted, authenticated remote HTTP for Cloud</summary>
|
|
852
|
+
|
|
853
|
+
Letta runs agents on a server, so attachment differs by deployment:
|
|
854
|
+
|
|
855
|
+
- **Self-hosted Letta** accepts a **stdio** MCP server via `PUT /v1/tools/mcp/servers` — no network exposure.
|
|
856
|
+
- **Letta Cloud** rejects stdio and needs a **remote streamable-HTTP** MCP URL behind authentication.
|
|
857
|
+
|
|
858
|
+
Both were verified live (an agent autonomously called `get_v1_attributes` from the Glama spec through the proxy). Full setup for both paths, including the supergateway wrapper and the security note for the Cloud endpoint, is in [`examples/letta/README.md`](examples/letta/README.md).
|
|
859
|
+
|
|
860
|
+
</details>
|
|
861
|
+
|
|
862
|
+
<details>
|
|
863
|
+
<summary><b>WordPress Example</b> — publish to a real WordPress blog from any MCP agent</summary>
|
|
864
|
+
|
|
865
|
+
This example turns the WordPress REST API into MCP tools so an agent can **create, read, update, and trash blog posts**. It is the example behind a real-world demonstration: a fleet of agent CLIs published to the live blog at **[matthewhand.mywebcommunity.org](https://matthewhand.mywebcommunity.org/)** through this proxy — see the write-up [*“Turning Any API into Agent Tools”*](https://matthewhand.mywebcommunity.org/2026/06/12/turning-any-api-into-agent-tools-a-real-world-test-of-mcp-openapi-proxy/), itself posted via the proxy.
|
|
866
|
+
|
|
867
|
+
Example config — `examples/wordpress-claude_desktop_config.json`:
|
|
868
|
+
|
|
869
|
+
```json
|
|
870
|
+
{
|
|
871
|
+
"mcpServers": {
|
|
872
|
+
"wordpress": {
|
|
873
|
+
"command": "uvx",
|
|
874
|
+
"args": ["mcp-openapi-proxy"],
|
|
875
|
+
"env": {
|
|
876
|
+
"OPENAPI_SPEC_URL": "https://raw.githubusercontent.com/matthewhand/mcp-openapi-proxy/main/examples/wordpress-openapi.json",
|
|
877
|
+
"SERVER_URL_OVERRIDE": "https://your-site.example.com/wp-json",
|
|
878
|
+
"EXTRA_HEADERS": "Authorization: Basic BASE64_OF_USERNAME_COLON_APPLICATION_PASSWORD",
|
|
879
|
+
"IGNORE_SSL_TOOLS": "false",
|
|
880
|
+
"TOOL_WHITELIST": "/wp/v2/posts"
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
Exposed tools (from the bundled `examples/wordpress-openapi.json`): `get_wp_v2_posts`, `post_wp_v2_posts` (create), `get_wp_v2_posts_by_id`, `post_wp_v2_posts_by_id` (update), and `delete_wp_v2_posts_by_id` (trash) — the full post lifecycle.
|
|
888
|
+
|
|
889
|
+
**Auth — use a WordPress *Application Password*, not your login password.** WordPress REST rejects login passwords for Basic auth. In `wp-admin → Users → (your user) → Application Passwords`, create one, then base64-encode `username:application-password` for the `EXTRA_HEADERS` value:
|
|
890
|
+
|
|
891
|
+
```bash
|
|
892
|
+
printf 'myuser:xxxx xxxx xxxx xxxx xxxx xxxx' | base64 -w0
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
Tips: set `IGNORE_SSL_TOOLS=true` only if your host serves a self-signed/mismatched cert; give each agent its own (revocable) application password; keep `TOOL_WHITELIST=/wp/v2/posts` so the agent can touch only posts.
|
|
896
|
+
|
|
897
|
+
</details>
|
|
898
|
+
|
|
849
899
|
## Troubleshooting
|
|
850
900
|
|
|
851
901
|
### JSON-RPC Testing
|
|
@@ -408,7 +408,7 @@ async def read_resource(request: types.ReadResourceRequest) -> types.ReadResourc
|
|
|
408
408
|
]
|
|
409
409
|
)
|
|
410
410
|
logger.debug("Dumping spec to JSON...")
|
|
411
|
-
spec_json = json.dumps(spec_data, indent=2)
|
|
411
|
+
spec_json = json.dumps(spec_data, indent=2, default=str)
|
|
412
412
|
logger.debug(f"Forcing spec JSON return: {spec_json[:50]}...")
|
|
413
413
|
return types.ReadResourceResult(
|
|
414
414
|
contents=[
|
|
@@ -14,6 +14,28 @@ from mcp import types
|
|
|
14
14
|
# Import the configured logger
|
|
15
15
|
from .logging_setup import logger
|
|
16
16
|
|
|
17
|
+
|
|
18
|
+
class _NoTimestampSafeLoader(yaml.SafeLoader):
|
|
19
|
+
"""SafeLoader that keeps unquoted RFC3339 timestamps as plain strings.
|
|
20
|
+
|
|
21
|
+
PyYAML's SafeLoader auto-converts values like ``2015-02-22T20:00:45.000Z``
|
|
22
|
+
into Python ``datetime`` objects. Such objects are not JSON-serializable,
|
|
23
|
+
which crashed spec caching and ``resources/read`` for specs that carry
|
|
24
|
+
datetime example values (e.g. the apis.guru directory spec). Loading specs
|
|
25
|
+
with this loader keeps every scalar JSON-safe.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
_NoTimestampSafeLoader.yaml_implicit_resolvers = {
|
|
30
|
+
key: [(tag, regexp) for tag, regexp in resolvers if tag != "tag:yaml.org,2002:timestamp"]
|
|
31
|
+
for key, resolvers in yaml.SafeLoader.yaml_implicit_resolvers.items()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def yaml_load_safe(content: str):
|
|
36
|
+
"""Parse YAML with timestamps preserved as strings (JSON-safe)."""
|
|
37
|
+
return yaml.load(content, Loader=_NoTimestampSafeLoader)
|
|
38
|
+
|
|
17
39
|
def setup_logging(debug: bool = False):
|
|
18
40
|
"""
|
|
19
41
|
Configure logging for the application.
|
|
@@ -196,7 +218,7 @@ def _spec_cache_store(url: str, spec: Dict) -> None:
|
|
|
196
218
|
try:
|
|
197
219
|
path = _spec_cache_path(url)
|
|
198
220
|
with open(path + ".tmp", "w") as f:
|
|
199
|
-
json.dump(spec, f)
|
|
221
|
+
json.dump(spec, f, default=str)
|
|
200
222
|
os.replace(path + ".tmp", path)
|
|
201
223
|
logger.debug(f"Cached spec for {url} at {path}")
|
|
202
224
|
except OSError as exc:
|
|
@@ -226,7 +248,7 @@ def fetch_openapi_spec(url: str, retries: int = 3) -> Optional[Dict]:
|
|
|
226
248
|
logger.debug(f"Using {spec_format.upper()} parser based on OPENAPI_SPEC_FORMAT env var")
|
|
227
249
|
if spec_format == "yaml":
|
|
228
250
|
try:
|
|
229
|
-
spec =
|
|
251
|
+
spec = yaml_load_safe(content)
|
|
230
252
|
logger.debug(f"Parsed as YAML from {url}")
|
|
231
253
|
except yaml.YAMLError as ye:
|
|
232
254
|
logger.error(f"YAML parsing failed: {ye}. Raw content: {content[:500]}...")
|
|
@@ -252,7 +274,7 @@ def fetch_openapi_spec(url: str, retries: int = 3) -> Optional[Dict]:
|
|
|
252
274
|
logger.debug(f"Parsed as JSON from {url}")
|
|
253
275
|
except json.JSONDecodeError:
|
|
254
276
|
try:
|
|
255
|
-
spec =
|
|
277
|
+
spec = yaml_load_safe(content)
|
|
256
278
|
logger.debug(f"Parsed as YAML from {url}")
|
|
257
279
|
except yaml.YAMLError as ye:
|
|
258
280
|
logger.error(f"YAML parsing failed: {ye}. Raw content: {content[:500]}...")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-openapi-proxy
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: MCP server for exposing OpenAPI specifications as MCP tools.
|
|
5
5
|
Author-email: Matthew Hand <11550632+matthewhand@users.noreply.github.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -31,10 +31,11 @@ Dynamic: license-file
|
|
|
31
31
|
- ✅ **Codex**, **Gemini**, **Qwen**, **Kilocode**, **opencode** — native tool calls over stdio
|
|
32
32
|
- ✅ **Vibe** — native discovery and read calls (writes were CLI-flaky, not a proxy issue)
|
|
33
33
|
- ✅ **Letta** — Cloud (via a remote streamable-HTTP MCP URL) and self-hosted (via stdio)
|
|
34
|
-
- ⚠️ **agy** — could not attach in headless mode; MCP tool enablement is interactive-only in agy (an agy limitation, not the proxy)
|
|
35
34
|
|
|
36
35
|
See the [client matrix](#client-matrix) for attach mechanisms, models, and exact results.
|
|
37
36
|
|
|
37
|
+
> 📄 Full write-up: [**Verification case study**](docs/verification-case-study.md) — what the proxy is, the API + client matrices, and every defect found & fixed.
|
|
38
|
+
|
|
38
39
|
**Prompts and resources are real now — including custom resources.** Both MCP surfaces are functional and tested: the `summarize_spec` / `whimsical_blog` prompts and the `spec_file` resource, plus a new `ADDITIONAL_RESOURCES` env var that serves your *own* use-case documents (e.g. a NetBox naming policy or an Asana project-layout guide) as MCP resources — see `examples/resources/`.
|
|
39
40
|
|
|
40
41
|
**Bug fixes (every one live-verified):**
|
|
@@ -63,7 +64,7 @@ Full environment-variable reference is in [Environment Variables](#environment-v
|
|
|
63
64
|
- [Environment Variables](#environment-variables)
|
|
64
65
|
- [Verified Clients & Live Results (2026-06-12)](#verified-clients--live-results-2026-06-12)
|
|
65
66
|
- [Tips](#tips)
|
|
66
|
-
- [Examples](#examples) — Glama, Fly.io, Render, Slack, GetZep, Virustotal, Notion, Asana, APIs.guru, NetBox, Box, WolframAlpha (collapsed)
|
|
67
|
+
- [Examples](#examples) — Glama, Fly.io, Render, Slack, GetZep, Virustotal, Notion, Asana, APIs.guru, NetBox, Box, WolframAlpha, WordPress (collapsed)
|
|
67
68
|
- [Troubleshooting](#troubleshooting)
|
|
68
69
|
- [License](#license)
|
|
69
70
|
|
|
@@ -868,6 +869,55 @@ You can now use the MCP ecosystem to list and invoke WolframAlpha API tools. For
|
|
|
868
869
|
|
|
869
870
|
</details>
|
|
870
871
|
|
|
872
|
+
<details>
|
|
873
|
+
<summary><b>Letta (self-hosted + Cloud)</b> — agent platform; stdio for self-hosted, authenticated remote HTTP for Cloud</summary>
|
|
874
|
+
|
|
875
|
+
Letta runs agents on a server, so attachment differs by deployment:
|
|
876
|
+
|
|
877
|
+
- **Self-hosted Letta** accepts a **stdio** MCP server via `PUT /v1/tools/mcp/servers` — no network exposure.
|
|
878
|
+
- **Letta Cloud** rejects stdio and needs a **remote streamable-HTTP** MCP URL behind authentication.
|
|
879
|
+
|
|
880
|
+
Both were verified live (an agent autonomously called `get_v1_attributes` from the Glama spec through the proxy). Full setup for both paths, including the supergateway wrapper and the security note for the Cloud endpoint, is in [`examples/letta/README.md`](examples/letta/README.md).
|
|
881
|
+
|
|
882
|
+
</details>
|
|
883
|
+
|
|
884
|
+
<details>
|
|
885
|
+
<summary><b>WordPress Example</b> — publish to a real WordPress blog from any MCP agent</summary>
|
|
886
|
+
|
|
887
|
+
This example turns the WordPress REST API into MCP tools so an agent can **create, read, update, and trash blog posts**. It is the example behind a real-world demonstration: a fleet of agent CLIs published to the live blog at **[matthewhand.mywebcommunity.org](https://matthewhand.mywebcommunity.org/)** through this proxy — see the write-up [*“Turning Any API into Agent Tools”*](https://matthewhand.mywebcommunity.org/2026/06/12/turning-any-api-into-agent-tools-a-real-world-test-of-mcp-openapi-proxy/), itself posted via the proxy.
|
|
888
|
+
|
|
889
|
+
Example config — `examples/wordpress-claude_desktop_config.json`:
|
|
890
|
+
|
|
891
|
+
```json
|
|
892
|
+
{
|
|
893
|
+
"mcpServers": {
|
|
894
|
+
"wordpress": {
|
|
895
|
+
"command": "uvx",
|
|
896
|
+
"args": ["mcp-openapi-proxy"],
|
|
897
|
+
"env": {
|
|
898
|
+
"OPENAPI_SPEC_URL": "https://raw.githubusercontent.com/matthewhand/mcp-openapi-proxy/main/examples/wordpress-openapi.json",
|
|
899
|
+
"SERVER_URL_OVERRIDE": "https://your-site.example.com/wp-json",
|
|
900
|
+
"EXTRA_HEADERS": "Authorization: Basic BASE64_OF_USERNAME_COLON_APPLICATION_PASSWORD",
|
|
901
|
+
"IGNORE_SSL_TOOLS": "false",
|
|
902
|
+
"TOOL_WHITELIST": "/wp/v2/posts"
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
Exposed tools (from the bundled `examples/wordpress-openapi.json`): `get_wp_v2_posts`, `post_wp_v2_posts` (create), `get_wp_v2_posts_by_id`, `post_wp_v2_posts_by_id` (update), and `delete_wp_v2_posts_by_id` (trash) — the full post lifecycle.
|
|
910
|
+
|
|
911
|
+
**Auth — use a WordPress *Application Password*, not your login password.** WordPress REST rejects login passwords for Basic auth. In `wp-admin → Users → (your user) → Application Passwords`, create one, then base64-encode `username:application-password` for the `EXTRA_HEADERS` value:
|
|
912
|
+
|
|
913
|
+
```bash
|
|
914
|
+
printf 'myuser:xxxx xxxx xxxx xxxx xxxx xxxx' | base64 -w0
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
Tips: set `IGNORE_SSL_TOOLS=true` only if your host serves a self-signed/mismatched cert; give each agent its own (revocable) application password; keep `TOOL_WHITELIST=/wp/v2/posts` so the agent can touch only posts.
|
|
918
|
+
|
|
919
|
+
</details>
|
|
920
|
+
|
|
871
921
|
## Troubleshooting
|
|
872
922
|
|
|
873
923
|
### JSON-RPC Testing
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mcp-openapi-proxy"
|
|
7
7
|
requires-python = ">=3.10"
|
|
8
|
-
version = "0.2.
|
|
8
|
+
version = "0.2.1"
|
|
9
9
|
description = "MCP server for exposing OpenAPI specifications as MCP tools."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
authors = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_openapi_proxy-0.2.0 → mcp_openapi_proxy-0.2.1}/mcp_openapi_proxy.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|