Workspace API Reference
All workspace management endpoints are mounted at /api/community/mcp/workspaces. Every request requires either a JWT Bearer token or an X-API-Key account key.
Authentication
All routes accept two authentication methods:
| Method | Header | Format |
|---|---|---|
| JWT Bearer | Authorization | Bearer eyJhbGci... |
| Account API Key | X-API-Key | ak_... |
Unauthenticated requests return 401 Unauthorized.
Workspaces
Create Workspace
POST /api/community/mcp/workspacesRequest Body:
{
"name": "My Workspace",
"description": "Optional description"
}| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | Yes | Min 2 characters |
description | string | No | Free-form text |
Response (201):
{
"id": "uuid",
"slug": "my-workspace",
"name": "My Workspace",
"description": "Optional description",
"gateway_url": "https://mcp.aerostack.dev/ws/my-workspace",
"created_at": 1710000000
}Errors:
| Status | Error | Cause |
|---|---|---|
| 400 | name is required (min 2 characters) | Missing or too short name |
| 403 | MCP workspace limit reached... | Plan workspace limit exceeded |
List Workspaces
GET /api/community/mcp/workspacesResponse (200):
{
"workspaces": [
{
"id": "uuid",
"slug": "my-workspace",
"name": "My Workspace",
"description": "...",
"status": "active",
"server_count": 3,
"gateway_url": "https://mcp.aerostack.dev/ws/my-workspace",
"created_at": 1710000000,
"updated_at": 1710000000
}
]
}Get Workspace
GET /api/community/mcp/workspaces/:idReturns the workspace with all its servers (joined with MCP server details).
Response (200):
{
"id": "uuid",
"slug": "my-workspace",
"name": "My Workspace",
"description": "...",
"status": "active",
"gateway_url": "https://mcp.aerostack.dev/ws/my-workspace",
"servers": [
{
"ws_server_id": "link-uuid",
"server_id": "server-uuid",
"slug": "@acme/github",
"name": "GitHub Tools",
"description": "GitHub integration",
"type": "skill",
"hosted": true,
"access_type": "public",
"star_count": 42,
"tool_count": 5,
"is_function": false,
"inject_secrets": ["GITHUB_TOKEN"],
"enabled": true,
"display_order": 0
}
],
"created_at": 1710000000,
"updated_at": 1710000000
}Update Workspace
PATCH /api/community/mcp/workspaces/:idRequest Body (all fields optional):
{
"name": "Updated Name",
"description": "Updated description"
}| Field | Type | Constraints |
|---|---|---|
name | string | Min 2 characters |
description | string | Free-form text |
Response (200):
{ "success": true }Updating a workspace name does not change the slug. The slug is immutable.
Delete Workspace
DELETE /api/community/mcp/workspaces/:idDeletes the workspace and all associated server links, tokens, and secrets.
Response (200):
{ "success": true }Servers
Add Server to Workspace
POST /api/community/mcp/workspaces/:id/serversRequest Body:
{
"server_id": "uuid",
"inject_secrets": ["SECRET_KEY_1", "SECRET_KEY_2"],
"display_order": 0
}Or, to add a community function (auto-wrapped as a skill):
{
"function_id": "uuid"
}| Field | Type | Required | Description |
|---|---|---|---|
server_id | string | One of server_id or function_id | Published MCP server UUID |
function_id | string | One of server_id or function_id | Deployed community function UUID |
inject_secrets | string[] | No | Secret key names to inject at call time |
display_order | number | No | Sort order (0-9999, lower first) |
Response (201):
{
"ws_server_id": "link-uuid",
"server_id": "resolved-uuid",
"name": "Server Name",
"slug": "@owner/server-slug"
}Errors:
| Status | Error | Cause |
|---|---|---|
| 400 | server_id or function_id is required | Neither provided |
| 403 | This skill is private... | Attempting to add a private server you do not own |
| 404 | MCP server not found or not published | Server does not exist or is not published |
| 409 | Server is already in this workspace | Duplicate server link |
| 422 | This function is not deployed yet... | Function must be deployed before adding |
Update Server in Workspace
PATCH /api/community/mcp/workspaces/:id/servers/:wsServerIdRequest Body (all fields optional):
{
"inject_secrets": ["GITHUB_TOKEN"],
"display_order": 2,
"enabled": true
}| Field | Type | Description |
|---|---|---|
inject_secrets | string[] | Secret key names to inject |
display_order | number | Sort order (0-9999) |
enabled | boolean | Enable or disable the server |
disabled | boolean | Inverted alias for enabled |
Response (200):
{ "success": true }Remove Server from Workspace
DELETE /api/community/mcp/workspaces/:id/servers/:wsServerIdResponse (200):
{ "success": true }Test Server Connectivity
POST /api/community/mcp/workspaces/:id/servers/:wsServerId/testSends a test request to the upstream server to verify connectivity and list available tools.
Response (200 — success):
{
"ok": true,
"tools_count": 5,
"tools": ["create_issue", "list_repos", "search_code", "get_pr", "merge_pr"]
}Response (200 — failure):
{
"ok": false,
"error": "HTTP 401: Unauthorized"
}Tokens
Issue Token
POST /api/community/mcp/workspaces/:id/tokensRequest Body:
{
"name": "Alice Cursor",
"expires_in": 2592000
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable label |
expires_in | number | No | Seconds until expiry |
expiry | number | No | Alias for expires_in |
Response (201):
{
"id": "token-uuid",
"token": "mwt_7a3f9c...",
"name": "Alice Cursor",
"expires_at": 1712592000,
"mcp_json": {
"mcpServers": {
"my-workspace": {
"url": "https://mcp.aerostack.dev/ws/my-workspace",
"headers": { "Authorization": "Bearer mwt_7a3f9c..." }
}
}
},
"warning": "Save this token now. It will not be shown again."
}The token field is returned only in this response. It cannot be retrieved later — save it immediately.
List Tokens
GET /api/community/mcp/workspaces/:id/tokensResponse (200):
{
"tokens": [
{
"id": "token-uuid",
"name": "Alice Cursor",
"active": true,
"last_used_at": 1710500000,
"created_at": 1710000000,
"revoked_at": null,
"expires_at": 1712592000
}
]
}Revoke Token
DELETE /api/community/mcp/workspaces/:id/tokens/:tokenIdSets revoked_at timestamp. The token stops working immediately.
Response (200):
{ "success": true }Secrets
List Secrets
GET /api/community/mcp/workspaces/:id/secretsReturns secret names only. Values are never returned.
Response (200):
{
"secrets": [
{
"id": "secret-uuid",
"key_name": "GITHUB_TOKEN",
"key": "GITHUB_TOKEN",
"created_at": 1710000000
}
]
}Create or Update Secret
POST /api/community/mcp/workspaces/:id/secretsRequest Body:
{
"key": "GITHUB_TOKEN",
"value": "ghp_abc123..."
}| Field | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Key name (auto-uppercased, sanitized to [A-Z0-9_]) |
key_name | string | No | Alias for key |
value | string | Yes | Secret value (encrypted at rest) |
Upsert behavior: if a secret with the same key name exists, the value is overwritten.
Response (201):
{
"id": "secret-uuid",
"key": "GITHUB_TOKEN",
"success": true
}Delete Secret
DELETE /api/community/mcp/workspaces/:id/secrets/:secretIdThe :secretId parameter accepts either a UUID or a key name (e.g. GITHUB_TOKEN).
Response (200):
{ "success": true }Errors:
| Status | Error | Cause |
|---|---|---|
| 404 | Secret not found | No secret matches the ID or key name |
Gateway Endpoints
These endpoints are on the gateway, not the management API. They require a workspace token (mwt_...) instead of a JWT.
MCP JSON-RPC Gateway
POST https://mcp.aerostack.dev/ws/:slug
Authorization: Bearer mwt_...
Content-Type: application/jsonSupported methods: initialize, ping, tools/list, tools/call
OpenAI Tools Adapter
GET https://mcp.aerostack.dev/ws/:slug/openai-tools
Authorization: Bearer mwt_...Gemini Tools Adapter
GET https://mcp.aerostack.dev/ws/:slug/gemini-tools
Authorization: Bearer mwt_...