Connecting an MCP client
Taskforce.sh exposes a standard Streamable HTTP MCP endpoint. Any MCP-capable client can connect to it using an agent token as a Bearer credential.
Endpoint
| Deployment | MCP endpoint |
|---|---|
| Taskforce.sh (hosted) | https://api.taskforce.sh/mcp |
| On-premises | https://<your-taskforce-host>/mcp |
Authentication is a bearer token header:
Authorization: Bearer tfa_…The endpoint is stateless: every JSON-RPC request is a POST, and there are no long-lived sessions or server-sent event streams. GET and DELETE return 405 Method not allowed.
In the examples below, replace tfa_your_token_here with a token created for your agent.
Cursor
Add Taskforce.sh to ~/.cursor/mcp.json (global) or .cursor/mcp.json (per project):
{
"mcpServers": {
"taskforce": {
"url": "https://api.taskforce.sh/mcp",
"headers": {
"Authorization": "Bearer tfa_your_token_here"
}
}
}
}VS Code (GitHub Copilot)
Add Taskforce.sh to .vscode/mcp.json. Using an inputs prompt keeps the token out of the file. VS Code asks for it once and stores it securely:
{
"inputs": [
{
"id": "taskforce-token",
"type": "promptString",
"description": "Taskforce agent token",
"password": true
}
],
"servers": {
"taskforce": {
"type": "http",
"url": "https://api.taskforce.sh/mcp",
"headers": {
"Authorization": "Bearer ${input:taskforce-token}"
}
}
}
}Claude Code
claude mcp add --transport http taskforce https://api.taskforce.sh/mcp \
--header "Authorization: Bearer tfa_your_token_here"Claude Desktop
Claude Desktop's claude_desktop_config.json only launches local (stdio) servers, and ignores url and headers entries. Connect it through the mcp-remote bridge, which runs locally and forwards requests to Taskforce.sh with your token (requires Node.js):
{
"mcpServers": {
"taskforce": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.taskforce.sh/mcp",
"--header",
"Authorization:${TASKFORCE_AUTH}"
],
"env": {
"TASKFORCE_AUTH": "Bearer tfa_your_token_here"
}
}
}
}TIP
The header value is passed through an environment variable, and the Authorization:${TASKFORCE_AUTH} argument has no space. This avoids argument-splitting problems some platforms have with spaces inside args.
Restart the client and the Taskforce.sh tools will appear. Ask it something like "What's failing in my welcome-emails queue?" and it will use the read tools to investigate.
Your own agent (MCP SDK)
Any MCP client library works. For example, with the TypeScript SDK:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("https://api.taskforce.sh/mcp"),
{
requestInit: {
headers: { Authorization: `Bearer ${process.env.TASKFORCE_TOKEN}` },
},
}
);
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);
// Discover what this agent is allowed to do
const perms = await client.callTool({ name: "get_permissions", arguments: {} });
// List accessible queues
const queues = await client.callTool({ name: "list_queues", arguments: {} });TIP
Have your agent call get_permissions first. It returns the teams the agent belongs to and the exact actions it may perform, so the agent can avoid attempting anything it isn't allowed to do.
Limits
To protect your queues (and the service) from a runaway or buggy agent, the MCP endpoint enforces these limits:
| Limit | Value | When exceeded |
|---|---|---|
| Requests per token | 120 per 60-second window | 429, with a Retry-After header |
| Request body size | 256 KB | 413 |
| Request duration | 30 seconds | 504 |
Job ids per bulk call (retry_jobs, promote_jobs, remove_jobs) | 100 | Validation error |
Jobs per page (list_jobs, list_failed_jobs) | 50 | Validation error |
These are the defaults on the hosted Taskforce.sh. Self-hosted installs can tune them, see Environment variables.
Every authenticated response includes rate-limit headers, so a well-behaved agent can slow down before it hits the limit:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per window |
X-RateLimit-Remaining | Requests left in the current window |
X-RateLimit-Reset | When the window resets (Unix time, seconds) |
Retry-After | Only on 429: seconds to wait before retrying |
TIP
Rate limits apply per token. If several independent agents or processes share one token, they share its budget. Give each its own token instead.
Errors you might see
HTTP errors
These are returned as an HTTP status with a JSON-RPC error body, for example {"jsonrpc":"2.0","error":{"code":-32001,"message":"Unauthorized: expired"},"id":null}.
| Status | Message | Meaning |
|---|---|---|
401 | Unauthorized: invalid_token | The token is missing, wrong, or was revoked |
401 | Unauthorized: expired | The token passed its expiry date |
401 | Unauthorized: agent_disabled | The owning agent is disabled |
405 | Method not allowed | Use POST. The endpoint is stateless |
413 | Request body too large | The request exceeded the body size limit |
429 | Rate limit exceeded | Slow down and retry after the Retry-After delay |
504 | Request timed out | The request exceeded the duration limit |
Tool errors
When the request is valid but a tool call can't be completed, the HTTP call succeeds and the tool result is flagged as an error (isError: true) with a message. MCP clients surface these to the model, so the agent can adjust:
| Message | Meaning |
|---|---|
Insufficient permission: can_… | The agent's role on that queue's team doesn't allow this action. See Permissions |
Agent is not a member of this queue's team | Add the agent to the team that owns the queue |
Queue is not accessible to agents | The queue is on a personal connection. Agents can only reach queues on team connections |
Queue not found | The queueId is wrong. Use an id from list_queues |
Error: Job … not found | The job id doesn't exist (it may have been removed) |
Permission and access failures are recorded in the audit log with a denied outcome.
With a read-only token, write tools aren't registered at all, so calling one fails as an unknown tool rather than a permission error.