HelpDesk MCP Server
The HelpDesk MCP (Model Context Protocol) server enables LLMs like Claude to create tickets, tasks, and interact with your HelpDesk system through natural language.
Overview
The MCP server is deployed as a Firebase Cloud Function (Gen 2, running on Cloud Run) and supports both HTTP and SSE transports. It exposes the following tools:
| Tool | Description |
|---|---|
create_ticket | Create a new support ticket |
create_task | Create a new task |
list_tickets | List tickets with optional status filter |
get_ticket | Get details of a specific ticket |
search_tickets | Search tickets by keyword |
add_ticket_reply | Add a reply to a ticket |
list_tasks | List tasks with optional status filter |
Getting an API Key
Option 1: Self-Service Portal (Recommended)
Users can generate their own API keys via the MCP Auth Portal:
- Visit
https://your-helpdesk-url/mcp - Sign in with Google
- Click “Create New Key”
- Enter a name for your key (e.g., “Claude Desktop”)
- Select your tenant
- Copy the key immediately - it won’t be shown again!
The portal also shows:
- All your existing API keys
- Usage statistics (last used, total calls)
- Ability to delete keys
Option 2: Legacy Static Key (Admin Only)
For backward compatibility, admins can set a shared API key:
# Generate a random API keyopenssl rand -hex 32
# Set it as a Firebase secretfirebase functions:secrets:set MCP_API_KEYNote: User-generated keys (starting with hdsk_) are preferred as they:
- Are tied to individual users for accountability
- Can be revoked without affecting other users
- Track usage per key
- Automatically associate with the correct tenant
Setup
1. Deploy the Function
Deploy the MCP function to Firebase:
cd /path/to/HelpDesk./deploy.sh --functions-onlyOr deploy just the MCP function:
firebase deploy --only functions:mcp3. Get the Function URL
After deployment, note the function URL. It will be displayed as:
Function URL (mcp(us-central1)): https://mcp-XXXXXX-uc.a.run.appThe actual URL for this project is:
https://mcp-a5kjn6gt4q-uc.a.run.appUsing with Claude Code
Claude Code supports MCP servers natively via SSE transport. Add a .mcp.json file to your project root:
{ "mcpServers": { "helpdesk": { "type": "sse", "url": "https://mcp-a5kjn6gt4q-uc.a.run.app/sse", "headers": { "X-API-Key": "your-api-key-here", "X-Tenant-ID": "default" } } }}Or add it via the CLI:
claude mcp add --transport sse --scope project helpdesk https://mcp-a5kjn6gt4q-uc.a.run.app/sse \ --header "X-API-Key: your-api-key-here" \ --header "X-Tenant-ID: default"After adding, restart Claude Code and verify the connection:
- Type
/mcpto see connected servers - The helpdesk server should show as “connected”
Important: Cloud Run IAM Settings
The MCP Cloud Run service must allow unauthenticated invocations:
- Go to Cloud Run console: https://console.cloud.google.com/run
- Click on the
mcpservice - Go to the Security tab
- Disable “Use IAM to authenticate incoming requests”
This allows Claude Code to connect while the MCP server still validates API keys in headers.
Using with Claude Desktop
Add the following to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{ "mcpServers": { "helpdesk": { "command": "npx", "args": [ "mcp-remote-client", "https://mcp-a5kjn6gt4q-uc.a.run.app" ], "env": { "MCP_API_KEY": "your-api-key-here", "MCP_TENANT_ID": "default" } } }}Note: You’ll need an MCP remote client that supports HTTP transport. Alternatively, you can use the server directly via HTTP or SSE.
Direct HTTP Usage
You can also call the MCP server directly via HTTP:
Initialize Connection
curl -X POST https://mcp-a5kjn6gt4q-uc.a.run.app \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -H "X-Tenant-ID: default" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {} }'List Available Tools
curl -X POST https://mcp-a5kjn6gt4q-uc.a.run.app \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }'Create a Ticket
curl -X POST https://mcp-a5kjn6gt4q-uc.a.run.app \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -H "X-Tenant-ID: default" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "create_ticket", "arguments": { "title": "Printer not working", "description": "The office printer on the 3rd floor is showing an error code E-501", "priority": "Medium", "name": "John Doe", "email": "[email protected]" } } }'Create a Task
curl -X POST https://mcp-a5kjn6gt4q-uc.a.run.app \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -H "X-Tenant-ID: default" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "create_task", "arguments": { "title": "Order new printer cartridges", "description": "Order replacement cartridges for the 3rd floor printer", "priority": 2, "deadline": "next week" } } }'Search Tickets
curl -X POST https://mcp-a5kjn6gt4q-uc.a.run.app \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -H "X-Tenant-ID: default" \ -d '{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "search_tickets", "arguments": { "query": "printer", "limit": 5 } } }'Multi-Tenant Support
The MCP server supports multi-tenancy. Pass the tenant ID in the X-Tenant-ID header:
-H "X-Tenant-ID: your-tenant-id"If not specified, it defaults to "default".
Tool Schemas
create_ticket
| Parameter | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Brief title describing the issue |
| description | string | Yes | Detailed description |
| priority | string | No | Urgent, High, Medium, Low, or Background (default: Medium) |
| name | string | Yes | Name of the submitter |
| string | Yes | Email of the submitter | |
| phone | string | No | Phone number |
| location | string | No | RCL, RCL-EH, My Home, or Other (default: Other) |
create_task
| Parameter | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Brief title for the task |
| description | string | Yes | Detailed description |
| priority | integer | No | 1-5 where 1 is highest (default: 3) |
| deadline | string | Yes | ISO date or “today”, “tomorrow”, “next week”, “X days” |
| assigneeName | string | No | Name of assignee |
list_tickets
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | No | Open, Resolved, Closed, On Hold, Waiting, or All (default: Open) |
| limit | integer | No | Max results, 1-50 (default: 10) |
get_ticket
| Parameter | Type | Required | Description |
|---|---|---|---|
| ticketId | string | Yes | The ticket ID to retrieve |
search_tickets
| Parameter | Type | Required | Description |
|---|---|---|---|
| query | string | Yes | Search query for title/description |
| limit | integer | No | Max results, 1-50 (default: 10) |
add_ticket_reply
| Parameter | Type | Required | Description |
|---|---|---|---|
| ticketId | string | Yes | The ticket ID to reply to |
| message | string | Yes | The reply message |
| authorName | string | Yes | Name of the person replying |
| authorEmail | string | Yes | Email of the person replying |
list_tasks
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | No | Created, Assigned, In Progress, Completed, Canceled, or All |
| limit | integer | No | Max results, 1-50 (default: 10) |
Security
Authentication
- All requests require a valid API key in the
X-API-Keyheader or as a Bearer token - Two types of keys are supported:
- User keys (format:
hdsk_...): Generated via the Auth Portal, tied to a Google account - Legacy keys: Static keys set via Firebase secrets (for backward compatibility)
- User keys (format:
Key Storage & Security
- User-generated keys are hashed (SHA-256) before storage - raw keys are never stored
- Keys are associated with the user’s Firebase UID and email for audit trails
- Usage statistics (last used, call count) are tracked automatically
Multi-Tenant Isolation
- Each key is associated with a specific tenant
- Users can only access data within their tenant
- Tenant ID can be overridden via
X-Tenant-IDheader if needed
Audit Trail
- Tickets created via MCP are marked with
submitterId: 'mcp-submission' - User-generated keys include the user’s identity in all operations
Troubleshooting
”Invalid or missing API key”
Ensure your API key matches the one set in Firebase secrets:
firebase functions:secrets:access MCP_API_KEY“Access denied to this ticket”
The ticket belongs to a different tenant. Check the X-Tenant-ID header matches the ticket’s tenant.
Cold Start Delays
The first request after idle may take 2-5 seconds due to Firebase cold start. Subsequent requests are faster.
Claude Code Shows “failed” Status
- Check Cloud Run IAM: Ensure “Use IAM to authenticate incoming requests” is disabled in Cloud Run Security settings
- Verify the URL: The SSE endpoint is
/sse, not the root URL - Restart Claude Code: After changing
.mcp.json, restart Claude Code - Test the endpoint manually:
You should see
Terminal window curl -H "X-API-Key: your-key" https://mcp-a5kjn6gt4q-uc.a.run.app/sseevent: endpointfollowed by a URL
Claude Code Shows “needs authentication”
This happens when OAuth fields are expected. The helpdesk MCP uses header-based authentication, not OAuth. Make sure your .mcp.json only contains type, url, and headers fields - no OAuth configuration.
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ | GET | Server info |
/ | POST | HTTP JSON-RPC transport |
/sse | GET | SSE transport connection |
/message | POST | SSE message endpoint (used by SSE clients) |