microsoft/ahp-client
>- Interact with an Agent Host Protocol (AHP) server via WebSocket. Use when asked to connect to, message, or control an AHP server.
npx skills add https://github.com/microsoft/agent-host-protocol --skill ahp-client
You have access to an MCP server (ahp-websocket) that lets you connect to an
Agent Host Protocol server over WebSocket and exchange JSON-RPC 2.0 messages.
| Tool | Purpose |
| ------------------- | ------------------------------------------------------------------------ |
| connect | Open (or re-open) a WebSocket to an AHP server URL |
| send | Send a JSON-RPC message and get the response + any pending notifications |
| get_notifications | Drain the notification inbox (optionally wait N seconds first) |
| status | Check connection state, pending request count, inbox depth |
| next_id | Get a unique incrementing integer for JSON-RPC request id fields |
1. connect(url: "ws://localhost:3000")
2. send initialize notification
3. wait for serverHello via get_notifications
4. subscribe to root state
5. create a session, subscribe, send turns
AHP is a Redux-inspired state synchronisation protocol built on JSON-RPC 2.0
over WebSocket. The server maintains an authoritative state tree; clients apply
actions optimistically and reconcile with the server's echoed actions.
Key concepts:
ahp-root://) – lists available agents/models.ahp-session:/<uuid>) – per-conversation state with turns,deltas, tool calls, and permissions.
ActionEnvelopes with aserverSeq.
receive action streams.
part of the state tree and NOT replayed on reconnect.
Send an initialize notification (no id field):
{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersions": ["0.3.0"],
"clientId": "<unique-client-id>",
"initialSubscriptions": ["ahp-root://"]
}
}
Then call get_notifications(wait: 2) to collect the serverHello response,
which includes snapshots for any initial subscriptions.
{
"jsonrpc": "2.0",
"id": 1,
"method": "subscribe",
"params": { "channel": "ahp-root://" }
}
The response contains the current state snapshot.
After subscribing, subsequent mutations arrive as action notifications.
{
"jsonrpc": "2.0",
"id": 2,
"method": "createSession",
"params": {
"session": "<provider>:/<uuid>",
"provider": "<provider>",
"model": "<model-id>"
}
}
Then subscribe to the session URI. Wait for a session/ready action.
Dispatch a session/turnStarted action as a notification (fire-and-forget):
{
"jsonrpc": "2.0",
"method": "dispatchAction",
"params": {
"channel": "<provider>:/<uuid>",
"clientSeq": 1,
"action": {
"type": "session/turnStarted",
"turnId": "<unique-turn-id>",
"userMessage": { "text": "Hello, world!" }
}
}
}
Then poll get_notifications(wait: 2) to collect streaming session/delta
actions until you see session/turnComplete.
If the agent calls a tool, the server sends:
session/toolStart – tool invocation startedsession/permissionRequest – user approval neededResolve permissions with:
{
"jsonrpc": "2.0",
"method": "dispatchAction",
"params": {
"channel": "<provider>:/<uuid>",
"clientSeq": 2,
"action": {
"type": "session/permissionResolved",
"turnId": "<turn-id>",
"requestId": "<perm-request-id>",
"approved": true
}
}
}
| Command | Purpose |
| ---------------- | ------------------------------------ |
| listSessions | List all session summaries |
| disposeSession | Tear down a session |
| resourceRead | Read content by URI reference |
| resourceList | List directory entries |
| resourceCopy | Copy a resource |
| resourceDelete | Delete a resource |
| resourceMove | Move/rename a resource |
| resourceWrite | Write content to a file |
| fetchTurns | Fetch historical turns for a session |
If the connection drops, call connect again and send a reconnect message
instead of initialize:
{
"jsonrpc": "2.0",
"method": "reconnect",
"params": {
"clientId": "<same-client-id>",
"lastSeenServerSeq": 42,
"subscriptions": ["ahp-root://", "<provider>:/<uuid>"]
}
}
| Action | Effect |
| ---------------------------- | ----------------------------------------- |
| session/turnStarted | Begin a new turn with a user message |
| session/permissionResolved | Approve or deny a pending tool permission |
| session/turnCancelled | Abort an in-progress turn |
| session/modelChanged | Switch the model for future turns |
| Action | Meaning |
| --------------------------- | ---------------------------------- |
| root/agentsChanged | Available agents or models changed |
| session/ready | Session backend initialized |
| session/creationFailed | Session failed to initialize |
| session/delta | Streaming text content for a turn |
| session/toolStart | Agent is calling a tool |
| session/toolDelta | Streaming tool output |
| session/toolComplete | Tool execution finished |
| session/permissionRequest | User approval needed for a tool |
| session/turnComplete | Turn finished |
| session/error | Error during turn |
For complete protocol details, refer to the docs in this repository:
docs/guide/ – conceptual overviews and walkthroughsgetting-started.md – end-to-end examplestate-model.md – full state tree shapeactions.md – how actions workreconciliation.md – write-ahead reconciliation algorithmdocs/specification/ – normative protocol spectransport.md – transport requirementslifecycle.md – connection, session, and reconnection lifecyclesubscriptions.md – subscription mechanicsversioning.md – version negotiationdocs/reference/ – complete type referencesmessages.md – all state typesactions.md – all action types with fieldscommands.md – all JSON-RPC commandsnotifications.md – all notification typeserror-codes.md – error code referenceRead these files when you need exact field names, type shapes, or edge-case
behaviour.
Take microsoft/ahp-client from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.