feat: add MCP server with OAuth 2.1 authentication#6266
feat: add MCP server with OAuth 2.1 authentication#6266danielgatis wants to merge 4 commits intoshellhub-io:masterfrom
Conversation
df02d62 to
610e9b4
Compare
|
/review |
|
Claude finished @otavio's task in 13m 10s —— View job Code Review CompleteReviewed 25 files. 5 inline issues posted (2 critical, 3 high).
Additional notesTesting gaps: Cross-repo impact: The
If you've addressed the feedback and want a new review, tag |
0291196 to
401679b
Compare
|
/review |
|
Claude finished @otavio's task in 4m 1s —— View job Code Review CompleteReviewed 25 files. 3 inline issues posted (2 critical, 1 high).
Additional notesCross-repo impact: Adding Testing gap: If you've addressed the feedback and want a new review, tag |
401679b to
3c89caa
Compare
|
/review |
|
Claude finished @otavio's task in 3m 15s —— View job Code Review CompleteReviewed 26 files. 5 inline issues posted (3 high, 1 high, 1 medium).
Additional notesCross-repo impact: Testing gap: The 11 MCP tool handlers in If you've addressed the feedback and want a new review, tag |
3c89caa to
67014b0
Compare
Implements OAuth 2.1 with PKCE, dynamic client registration (RFC 7591), authorization server metadata (RFC 8414), and exposes a Streamable HTTP MCP server at /mcp with device, session, and namespace tools.
67014b0 to
a981968
Compare
Summary
ShellHub now exposes an MCP (Model Context Protocol) server so AI assistants (Claude Desktop, Claude Code, Cursor, etc.) can manage devices, sessions, and namespaces directly.
The MCP server runs inside the
apiservice — no extra binary or sidecar needed. It uses OAuth 2.1 Authorization Code + PKCE for authentication, issuing the same JWT the rest of ShellHub uses.demo.mp4
How it works
The
access_tokenis a standard ShellHub JWT (RS256, 72 h). The MCP server validates it on every request.Connect Claude Code (CLI)
Or via the MCP Inspector to test:
Tool reference
All tools require a valid Bearer token. Permission levels:
observer<operator<administrator<owner.Device tools
shellhub_list_devicesList devices in the namespace.
statusaccepted,pending,rejected,removed,unusedpageper_pageMinimum permission:
observerOutput:
{ "total": N, "devices": [...] }shellhub_get_deviceGet full details of a single device.
uidMinimum permission:
observerOutput: Device object with status, tags, last seen, namespace, etc.
shellhub_update_device_statusAccept or reject a pending device.
uidstatusacceptedorrejectedMinimum permission:
operator(accept),operator(reject)shellhub_delete_devicePermanently delete a device. Irreversible.
uidMinimum permission:
administratorshellhub_rename_deviceRename a device (changes its hostname-style name).
uidnamemy-server)Minimum permission:
operatorshellhub_get_statsGet namespace statistics.
Minimum permission: any authenticated user
Output:
{ "registered_devices": 42, "online_devices": 17, "pending_devices": 3, "rejected_devices": 1, "active_sessions": 5 }Session tools
shellhub_list_sessionsList SSH sessions (active and historical).
pageper_pageMinimum permission:
observerOutput:
{ "total": N, "sessions": [...] }shellhub_get_sessionGet details of a specific session.
uidMinimum permission:
observerNamespace tools
shellhub_list_namespacesList namespaces accessible to the authenticated user.
pageper_pageMinimum permission: any authenticated user
Output:
{ "total": N, "namespaces": [...] }shellhub_get_namespaceGet namespace details including settings (session recording, device auto-accept, etc.).
tenant_idMinimum permission: any authenticated user
OAuth flow in detail
GET /.well-known/oauth-authorization-serverto find endpoints.code_verifier(random 32+ bytes, base64url) andcode_challenge = base64url(sha256(code_verifier)).GET /api/oauth/authorize?client_id=...&redirect_uri=...&code_challenge=...&code_challenge_method=S256&state=..../login?oauth_client_id=.... User logs in via normal ShellHub UI.POST /api/oauth/authorize/callbackwith the auth context. API issues a short-lived code (5 min, stored in Redis).POST /api/oauth/tokenwithgrant_type=authorization_code,code,code_verifier,client_id,redirect_uri. API verifies PKCE, deletes the code, returns a ShellHub JWT.Authorization: Bearer <jwt>on every MCP request.Managing OAuth clients
Troubleshooting
401 on
/mcp— token missing or expired. Re-authenticate via OAuth flow.forbidden: insufficient permissions— your role lacks the required permission. Check your role in the namespace settings.device is offline— device is not connected to ShellHub. Check device agent status.OAuth client not found —
client_idmismatch or client was deleted. Re-register the client.redirect_uri not allowed— theredirect_uriin the authorize request must exactly match one registered for the client.Test plan
POST /api/oauth/registerreturns a validclient_id/client_secretfor unauthenticated dynamic registrationGET /.well-known/oauth-authorization-serverreturns the issuer metadataPOST /mcpwith invalid token returns tool errorunauthorizedPOST /mcpwith valid token responds with the MCP capabilities and tool listshellhub_list_devices,shellhub_get_namespace, etc. returns expected dataforbidden: insufficient permissionsfor under-privileged roles