Skip to main content

Make Your First Gateway Call with a Machine User

This tutorial takes you from nothing to a working, authenticated tool call against the Willow gateway using a machine user and curl. Machine users are API accounts for bots, scripts, and automations, so this is the path to reach your MCP tools programmatically rather than through an interactive AI client.

By the end, you will have:

  • created a machine user and revealed its credentials
  • given it access to an MCP server through a group
  • completed the MCP handshake against the gateway
  • listed the tools the machine user can reach
  • called one of those tools and seen the result

Prerequisites

You need:

  • admin access to Willow
  • a deployed Willow MCP gateway
  • at least one published MCP server with tools enabled
  • curl or any HTTP client

If you have not published an MCP server yet, complete Add and Configure Your First MCP Server first. A machine user with no MCP servers in its groups has nothing to call.

Step 1: Create a machine user

In the admin dashboard, open Manage > Machine Users and select Add Machine User. Enter a name and select Save.

Machine Users page with the Name, Slug, Access Key, Secret, Owners, and Client Credentials columns and an Add Machine User button

Each machine user has an Access Key and a Secret. On the machine user's row, select the eye icon in the Access Key and Secret columns to reveal each value, and copy both. You will send them together as the bearer token.

Step 2: Give the machine user access through a group

A machine user only reaches tools from the MCP servers assigned to the groups it belongs to. Open Manage > Groups, open the row menu for a group that has your MCP server assigned, and select Edit Users. Check your machine user and select Done.

If you skip this step, the handshake still succeeds but tools/list comes back empty.

Step 3: Complete the MCP handshake

Your gateway URL is the Your Basecamp link in the top bar of the admin app, with /mcp appended (for example https://your-org.mcp-s.com/mcp).

Authenticate by joining the access key and secret with a colon and sending them as a bearer token. Send an initialize request to open the MCP session:

curl -X POST https://your-org.mcp-s.com/mcp \
-H "Authorization: Bearer <ACCESS_KEY>:<SECRET>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": { "name": "my-script", "version": "0.1" }
}
}'

A successful response confirms the session and identifies the gateway:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": { "tools": {}, "prompts": {}, "resources": {} },
"serverInfo": { "name": "mcp-s", "version": "1.0.0" }
}
}

Both halves of the credential are required. Sending the access key or the secret on its own returns 401 Unauthorized with {"error": "invalid_token"}.

Step 4: List the tools you can reach

Ask the gateway for the tools available to this machine user:

curl -X POST https://your-org.mcp-s.com/mcp \
-H "Authorization: Bearer <ACCESS_KEY>:<SECRET>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}'

Tools come back namespaced by their MCP server, in the form {server-slug}__{tool}. For example, a search-messages tool on a server with the slug slack appears as slack__search-messages. If the list is empty, the machine user is not in a group that has an MCP server assigned (revisit Step 2).

Step 5: Call a tool

Use a tool name from the previous response in a tools/call request:

curl -X POST https://your-org.mcp-s.com/mcp \
-H "Authorization: Bearer <ACCESS_KEY>:<SECRET>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": { "name": "slack__search-messages", "arguments": {} }
}'

The response contains the tool's output under result.content.

Verify it worked

You are done when all of these are true:

  • the machine user appears in the Machine Users table
  • the initialize call returns a result with serverInfo.name of mcp-s
  • tools/list returns at least one tool, namespaced {server}__{tool}
  • a tools/call returns a result
  • the call appears in Monitor > Logs, attributed to the machine user

Next steps