| name | maia-mcp-bridge |
| description | Spin up an HTTP/SSE wrapper around a stdio MCP server so Maia (Studio Pro 11.8+ MCP Client) can register it. Maia accepts only HTTP-Streamable or SSE — NOT stdio — so any MCP registered with Claude Code via `claude mcp add` (which is mostly stdio) is invisible to Maia by default. This skill emits a one-process HTTP bridge plus the exact Maia-Chat configuration steps Neo pastes into Studio Pro. Auto-invoke when Neo says "make X available in Maia", "wire MCP X to Maia", "register Y in Studio Pro AI", or types `/maia-mcp-bridge <mcp-name>`. Read the Maia MCP reference before running: https://docs.mendix.com/refguide/maia-mcp/ |
maia-mcp-bridge
Closes the stdio↔Maia gap. Without this skill, every stdio MCP Neo has working in Claude Code is invisible to Maia inside Studio Pro.
When to invoke
- Neo says: "make X available in Maia", "wire MCP X to Maia", "register the inventory MCP in Studio Pro", "let Maia see ".
mendix-doer Phase 6 (MCP advisory) determines a stdio MCP is needed in Maia for the current plan.
- Explicit:
/maia-mcp-bridge <mcp-name>.
Do NOT invoke for:
- An MCP that's already HTTP/SSE-served (e.g.,
mendix-context HTTP on :9123, playwright HTTP on :8931 — both registered as scheduled tasks). Check first via claude mcp list for non-stdio entries.
- A Mendix-context-mcp request (already covered by
MendixContextHttp scheduled task).
Inputs
mcp-name — exact name of the registered Claude Code MCP (claude mcp list shows it). Required.
- (optional)
--port — preferred local port (default: pick the next free port in the 9100-9199 range, document it).
- (optional)
--auth — none | bearer | oauth2.1 (default: none for local; recommend bearer for anything writing to a project).
Phase 1 — Verify the source MCP exists and is healthy
claude mcp list 2>&1 | Select-String "<mcp-name>"
Must show ✓ Connected. If not connected, STOP — fix the source MCP first; don't bridge a broken server.
Phase 2 — Detect transport
The source MCP entry tells you the command. If it's already HTTP/SSE (http://... or (SSE)), say so and exit:
" is already HTTP/SSE-served at . Maia can register it directly. No bridge needed."
If it's stdio (most uv run / python / npx registrations), proceed.
Phase 3 — Bridge architecture
The bridge is a thin HTTP-Streamable proxy in front of the stdio process. Two implementation paths:
Path A — Native HTTP transport on the source MCP (preferred when available)
Many MCP servers built with FastMCP already support HTTP via a flag. Check the server's CLI:
# Example for mendix-inventory (which already has --transport):
uv --directory "C:\Workspace\MendixToolkit\mcp-servers\mendix-inventory" run mendix-inventory --transport sse --port 9103
If the source MCP supports --transport sse|streamable-http, use that — no proxy needed. This is the preferred path because it's one process, not two.
For each MendixToolkit MCP, check the server file's argparse for --transport. If present, this is path A.
Path B — Generic stdio→HTTP proxy (when the source doesn't natively serve HTTP)
Use the official @modelcontextprotocol/server-runner or the Python mcp.server.streamable_http wrapper. The pattern:
import subprocess, sys
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
This is the fallback. Document the proxy file location, the port it binds, the source-stdio command it spawns.
Phase 4 — Decide deployment shape
Two flavors:
| Flavor | When | Lifecycle |
|---|
| Manual run (one-shot for a specific session) | quick test, one-off Maia experiment | Neo runs the command in a terminal; ctrl-c when done |
| Scheduled task (always-on) | the MCP is needed in Maia routinely | Register \MendixToolkit\<McpName>Http scheduled task at-logon, modeling after MendixContextHttp |
Default to manual for the first bridge of any MCP. Promote to scheduled task only after Neo confirms it's load-bearing.
For the scheduled-task pattern, see setup-scheduled-mendix-context-http.ps1 in the MendixToolkit repo root — copy and adapt.
Phase 5 — Choose port + URL
Pick a port from the 9100-9199 range that isn't already bound:
1..99 | ForEach-Object {
$p = 9100 + $_
if (-not (Get-NetTCPConnection -LocalPort $p -State Listen -ErrorAction SilentlyContinue)) {
$p
return
}
} | Select-Object -First 1
The full Maia-side URL pattern:
- Streamable HTTP:
http://localhost:<port>/mcp
- SSE:
http://localhost:<port>/sse
Per the Maia MCP doc, HTTP-Streamable is the recommended transport; SSE is legacy.
Phase 6 — Verify the bridge is reachable
After starting (manual or scheduled-task):
# For Streamable HTTP — POST a tools/list request
$body = @{ jsonrpc='2.0'; id=1; method='tools/list' } | ConvertTo-Json
$r = Invoke-WebRequest -Uri "http://localhost:<port>/mcp" -Method POST -Body $body -ContentType 'application/json' -UseBasicParsing
$r.StatusCode # expect 200
($r.Content | ConvertFrom-Json).result.tools | Select-Object -First 3 -Property name
If 200 + tools list returns: bridge is alive. If timeout / 5xx: STOP, debug; do not hand Neo a broken URL.
Phase 7 — Emit Maia-Chat configuration steps (the human-in-loop sheet)
Output a copy-paste-ready instruction block:
## Register `<mcp-name>` in Maia (Studio Pro 11.8+)
1. Open Studio Pro on a project on the testbed allowlist (TestOSApp3).
2. Open **Maia Chat** (Edit menu or sidebar).
3. Click the **Settings/Configure** gear → **MCP Connections** → **Add Server**.
4. Fill in:
- **Server Name:** `<mcp-name>` (use the same name; Maia uses this in tool listings)
- **URL:** `http://localhost:<port>/mcp`
- **Connection type:** HTTP Streamable
- **Authentication:** <none | Bearer Token | OAuth 2.1>
- (if Bearer) **Token:** `op://Personal/MaiaMcpBridge-<mcp-name>/token` — never paste the actual token.
5. Click **Save**.
6. Toggle the server to **Enabled** (default-disabled per Maia design).
7. Toggle individual tools to **Enabled** as needed (default-disabled).
8. Test in chat: type a question that should invoke a tool from `<mcp-name>` (e.g. "use <mcp-name>'s deep_context on ContentPortal_Home"). Maia should call the tool and return structured output.
Doc reference: https://docs.mendix.com/refguide/maia-mcp/
Phase 8 — Update the registry
Track the bridge in ~/.claude/state/maia-mcp-bridges.json:
{
"<mcp-name>": {
"transport": "streamable-http | sse",
"url": "http://localhost:<port>/mcp",
"lifecycle": "manual | scheduled-task",
"scheduled_task": "\\MendixToolkit\\<McpName>Http",
"registered_in_maia": "<YYYY-MM-DD or pending>",
"auth": "none | bearer | oauth2.1",
"created": "2026-04-29"
}
}
This registry lets future sessions answer "what's already bridged?" without re-deriving.
Banned shortcuts
- Never bridge an MCP that the doer's plan doesn't actually need in Maia. Bridging adds an HTTP endpoint that's a small but real attack surface; only bridge when there's a concrete Maia use-case.
- Never use HTTP without auth on anything that writes to a
.mpr. Read-only tools (most of mendix-inventory, all of mendix-context) are OK with none. Anything that gates a write (mxcli exec, mendix-doer's skill calls) needs Bearer.
- Never claim "Maia can use it" until Phase 7's test in chat actually returns a tool response. Per
~/.claude/CLAUDE.md "no faking complete."
- Never paste real tokens into the Maia config or this skill's output. Use
op:// references; per ~/.claude/rules/secrets.md.
Cross-references
- Maia MCP doc: https://docs.mendix.com/refguide/maia-mcp/
- Maia + Extensibility research brief:
~/.claude/wiki/pages/mendix/maia-extensibility-2026-04-29.md
- Existing HTTP-served MCP scheduled tasks:
MendixToolkit/setup-scheduled-mendix-context-http.ps1, setup-scheduled-playwright-http.ps1
- MCP-server design rules:
~/.claude/rules/mcp-server.md
mendix_inventory MCP server (which has --transport sse|streamable-http flag built-in for path A): C:\Workspace\MendixToolkit\mcp-servers\mendix-inventory\src\mendix_inventory\server.py