Skip to content

Commit 9f6f7d4

Browse files
committed
chore: cleanup
1 parent c78a6f1 commit 9f6f7d4

File tree

4 files changed

+43
-33
lines changed

4 files changed

+43
-33
lines changed

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A minimalist, terminal-based chat CLI built to explore the new [Claude Agent SDK](https://docs.claude.com/en/api/agent-sdk/overview) and based on [damassi/agent-chat-cli](https://github.com/damassi/agent-chat-cli). Terminal rendering is built on top of [React Ink](https://github.com/vadimdemedes/ink).
44

5-
Additionally, via inference, Agent Chat CLI supports lazy, turn-based MCP connections to keep token costs down. The agent will only use those MCP servers you ask about, limiting the context that is sent up to the LLM. (After an MCP server is connected it remains connected, however.)
5+
Additionally, via inference, Agent Chat CLI supports lazy, turn-based MCP connections to keep token costs down and performance reasonable. The agent will only use those MCP servers you ask about, limiting the context that is sent up to the LLM. (After an MCP server is connected it remains connected, however.)
66

77
## Overview
88

@@ -75,7 +75,9 @@ Run the agent in interactive terminal mode:
7575
bun start
7676
```
7777

78-
You'll see a prompt where you can type your questions or requests.
78+
You'll see a prompt where you can type your questions or requests. If you send it a general "Help!" query it will generate a help menu based upon configured MCP servers, if said MCP servers have corresponding system prompts in the `prompts` folder:
79+
80+
<img width="813" height="590" alt="Image" src="https://github.com/user-attachments/assets/2350639a-fb12-496a-9b32-b484fc14b8af" />
7981

8082
Type `exit` to quit.
8183

@@ -115,6 +117,8 @@ const config = {
115117
systemPrompt: getPrompt("system.md"),
116118
mcpServers: {
117119
someMcpServer: {
120+
description:
121+
"A detailed description of the MCP server and its capabilities used to provide hints to inference agent",
118122
command: "bunx",
119123
args: ["..."],
120124
prompt: getPrompt("someMcpServer.md"),
@@ -123,6 +127,8 @@ const config = {
123127
}
124128
```
125129

130+
The `description` field is **critical**; it's used by the inference routing agent to determine when to invoke the server or subagent.
131+
126132
#### Remote Prompts
127133

128134
Prompts can be loaded from remote sources (e.g., APIs) using `getRemotePrompt`. This enables dynamic prompt management where prompts are stored in a database or CMS rather than in files.
@@ -236,8 +242,6 @@ When a user asks something like "Analyze partner churn", the routing agent will:
236242
2. Automatically connect to the required `salesforce` MCP server
237243
3. Invoke the subagent with its specialized prompt and tools
238244

239-
The `description` field is **critical**; it's used by the routing agent to determine when to invoke the subagent.
240-
241245
**Note:** Subagents also support remote prompts via `getRemotePrompt`, allowing you to manage agent prompts dynamically from an API or database.
242246

243247
### Note on Lazy MCP Server Initialization

src/hooks/useAgent.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,7 @@ export function useAgent() {
117117
}
118118

119119
if (!message.is_error) {
120-
actions.setStats(
121-
`Completed in ${(message.duration_ms / 1000).toFixed(
122-
2
123-
)}s | Cost: $${message.total_cost_usd.toFixed(4)} | Turns: ${
124-
message.num_turns
125-
}`
126-
)
120+
actions.setStats(message)
127121
} else {
128122
actions.setStats(`[agent-cli] Error: ${message.subtype}`)
129123
}

src/mcp/getMcpServer.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { z } from "zod"
55

66
export const getMcpServer = () => {
77
// Store Claude Agent SDK sessionId per-instance (not shared across threads)
8-
let claudeSessionId: string | undefined
8+
let sessionId: string | undefined
99

1010
// Map thread IDs to Claude Agent SDK session IDs for per-thread isolation
1111
const threadSessions = new Map<string, string>()
@@ -35,23 +35,23 @@ export const getMcpServer = () => {
3535
},
3636
},
3737
async ({ query }) => {
38-
const existingConnectedServers = claudeSessionId
39-
? sessionConnectedServers.get(claudeSessionId)
38+
const existingConnectedServers = sessionId
39+
? sessionConnectedServers.get(sessionId)
4040
: undefined
4141

4242
const { response, connectedServers } = await runStandaloneAgentLoop({
4343
prompt: query,
4444
mcpServer,
45-
sessionId: claudeSessionId,
45+
sessionId,
4646
existingConnectedServers,
4747
onSessionIdReceived: (newSessionId) => {
48-
claudeSessionId = newSessionId
48+
sessionId = newSessionId
4949
},
5050
})
5151

5252
// Update the session's connected servers
53-
if (claudeSessionId) {
54-
sessionConnectedServers.set(claudeSessionId, connectedServers)
53+
if (sessionId) {
54+
sessionConnectedServers.set(sessionId, connectedServers)
5555
}
5656

5757
return {

src/store.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
McpServerConfig,
33
PermissionMode,
4+
SDKResultMessage,
45
} from "@anthropic-ai/claude-agent-sdk"
56
import {
67
action,
@@ -41,16 +42,17 @@ export interface ToolDenied {
4142
export type ChatHistoryEntry = Message | ToolUse | ToolDenied
4243

4344
type McpServerConfigWithPrompt = McpServerConfig & {
45+
/** A detailed description of the MCP server that the inference agent evaluates */
4446
description: string
45-
prompt?: () => Promise<string>
4647
disallowedTools?: string[]
4748
enabled?: boolean
49+
prompt?: () => Promise<string>
4850
}
4951

5052
export interface AgentChatConfig {
5153
agents?: Record<string, AgentConfig>
52-
disallowedTools?: string[]
5354
connectionTimeout?: number
55+
disallowedTools?: string[]
5456
maxRetries?: number
5557
mcpServers: Record<string, McpServerConfigWithPrompt>
5658
model?: "sonnet" | "haiku"
@@ -61,8 +63,8 @@ export interface AgentChatConfig {
6163
}
6264

6365
export interface PendingToolPermission {
64-
toolName: string
6566
input: any
67+
toolName: string
6668
}
6769

6870
export interface StoreModel {
@@ -80,9 +82,9 @@ export interface StoreModel {
8082
stats?: string | null
8183

8284
// Computed
83-
isBooted: Computed<StoreModel, boolean>
84-
availableMcpServers: Computed<StoreModel, string[]>
8585
availableAgents: Computed<StoreModel, string[]>
86+
availableMcpServers: Computed<StoreModel, string[]>
87+
isBooted: Computed<StoreModel, boolean>
8688

8789
// Actions
8890
abortRequest: Action<StoreModel>
@@ -91,6 +93,7 @@ export interface StoreModel {
9193
appendCurrentAssistantMessage: Action<StoreModel, string>
9294
clearCurrentAssistantMessage: Action<StoreModel>
9395
clearToolUses: Action<StoreModel>
96+
handleMcpServerStatus: Thunk<StoreModel, McpServerStatus[]>
9497
reset: Action<StoreModel>
9598
sendMessage: Action<StoreModel, string>
9699
setPendingToolPermission: Action<
@@ -105,23 +108,22 @@ export interface StoreModel {
105108
setIsProcessing: Action<StoreModel, boolean>
106109
setMcpServers: Action<StoreModel, McpServerStatus[]>
107110
setSessionId: Action<StoreModel, string>
108-
setStats: Action<StoreModel, string | null>
109-
handleMcpServerStatus: Thunk<StoreModel, McpServerStatus[]>
111+
setStats: Action<StoreModel, SDKResultMessage | null | string>
110112
}
111113

112114
export const AgentStore = createContextStore<StoreModel>({
113115
abortController: new AbortController(),
114116
chatHistory: [],
115-
messageQueue: new MessageQueue(),
116-
sessionId: undefined,
117-
mcpServers: [],
118-
input: "",
119-
isProcessing: false,
117+
config: null as unknown as AgentChatConfig,
120118
currentAssistantMessage: "",
121119
currentToolUses: [],
120+
input: "",
121+
isProcessing: false,
122+
mcpServers: [],
123+
messageQueue: new MessageQueue(),
122124
pendingToolPermission: undefined,
125+
sessionId: undefined,
123126
stats: undefined,
124-
config: null as unknown as AgentChatConfig,
125127

126128
// Computed
127129
isBooted: computed((state) => {
@@ -187,8 +189,18 @@ export const AgentStore = createContextStore<StoreModel>({
187189
state.currentToolUses.push(payload)
188190
}),
189191

190-
setStats: action((state, payload) => {
191-
state.stats = payload
192+
setStats: action((state, message) => {
193+
if (!message) {
194+
state.stats = null
195+
return
196+
}
197+
198+
if (typeof message === "string") {
199+
state.stats = message
200+
return
201+
}
202+
203+
state.stats = `Completed in ${(message.duration_ms / 1000).toFixed(2)}s | Cost: $${message.total_cost_usd.toFixed(4)} | Turns: ${message.num_turns}`
192204
}),
193205

194206
clearCurrentAssistantMessage: action((state) => {

0 commit comments

Comments
 (0)