Skip to content
WIP

This guide is a work in progress. Barry is also a work in progress.

@barry-rocks/sdk/tools

Helpers for writing tools: the tool contract (defineTool, the same function as Barry.Tool, and its ToolContext), definePrompt for prompt contributors, resolveSessionId, resolveUserPath, result capping, and mcpResult for returning native MCP content. It also holds the adapters that present tools on a command line and over MCP.

import { … } from "@barry-rocks/sdk/tools";
Property Type
currentContext () => ToolContext | undefined
registerMcpResources (server, context) => void
tools AnyToolDefinition[]

Property Type
access Record<string, "read" | "write">
namespace string
register (server) => void
secrets string[]

Property Type Description
limit? number Max characters to keep. Defaults to the env-resolved limit.
marker? string Storage callers can use a shorter marker; agents need the narrowing advice.
mode? "head" | "tail" Which end of the text to keep. Head for listings; tail for logs/errors.

Property Type Description
omitted number Characters removed (0 when not truncated).
text string -
truncated boolean -

Property Type
choices? string[]
coerce? (value) => unknown
defaultValue? unknown
description string
flags string
required boolean

Property Type
description string
key string
syntax string

Property Type
command string
description string
excluded boolean
keyMap Map<string, string>
options CliOption[]
positional CliPositional | null

Property Type
destructiveHint? boolean
idempotentHint? boolean
openWorldHint? boolean
readOnlyHint? boolean
title? string

registerTool(name, config, handler): unknown

Parameter Type
name string
config McpToolConfig
handler (args, extra) => Promise<unknown>

unknown

resource(…args): unknown

Parameter Type
…args unknown[]

unknown


Property Type
_meta? Record<string, unknown>
annotations? Record<string, unknown>
description? string
inputSchema? Record<string, unknown>

Context supplied to a bag’s computed prompt entry.

Property Type
cwd string
provider? string
repo? string
sessionId? string

One complete section contributed to the system prompt.

Property Type
text string

Property Type Description
onToolCall? (event) => void -
resultCharLimit? number Off by default; the consuming host chooses its output budget.

Property Type Description
availableTools? string[] For describing capabilities only; the host enforces authorization.
bagNames? string[] Bags this session’s identity enabled, composition already expanded — the same set that built the session’s prompt. Present only when a session with an identity was resolved. Catalog tools scope their listings to this so they describe what the session actually has. search_instructions promises “available to this session” and find_actions reads as a session listing; both enumerated every bag on the machine instead, because the option to scope them existed and nothing passed it. Descriptive, not authorization — the same contract as availableTools. ABSENT MEANS UNKNOWN, NOT EMPTY: an anonymous session (no identity) and the CLI both arrive without it, and must keep seeing everything. Scoping those to nothing would render an empty catalog indistinguishable from a machine with no instructions installed. Bag REGISTRY names, not tool namespaces. The two diverge — datadog-mcp serves the datadog namespace — and the instruction and action catalogs both match on registry name.
secrets Record<string, string> -
sessionId? string Prefer this over the environment in a server shared by multiple sessions.

Type Parameter Default type
T extends ToolShape ToolShape
R unknown
Property Type Description
_meta? Record<string, unknown> -
access "read" | "write" -
annotations? McpAnnotations -
cliFormat? (result) => string -
deferred? boolean Barry’s host can hide callable tools until tool_search discovers them.
description string -
handler (params, context?) => Promise<R> -
name string -
namespace string -
outputSchema? Record<string, unknown> JSON Schema avoids tying result contracts to a particular Zod version.
schema T -
secrets? string[] -

AnyToolDefinition = ToolDefinition<any, any>


ListToolsHandler = (request, extra) => Promise<{ tools?: Record<string, unknown>[]; }>

Normalize the JSON Schema this server puts on the wire.

The SDK converts each tool’s zod schema when it answers tools/list, picking its converter from the major that BUILT the schema – so without this, a bag’s published contract changes when its author bumps zod. Wrapping the handler is the only place to catch it: registerTool takes a zod schema, not JSON Schema, so there is nothing to normalize on the way in.

The SDK keeps its handlers in a private _requestHandlers map with no public getter. Reading it is load-bearing: if a REAL server has the map but no tools/list handler in it, the SDK’s internals moved and we must NOT silently skip – that would ship an un-normalized schema while every test stayed green – so that case throws. A server with no map at all is a test double with no wire to protect, and is skipped.

Idempotent and version-agnostic, so it is safe on a server whose tools came from several realms at once – the normal case for a bag host.

Parameter Type
request unknown
extra unknown

Promise<{ tools?: Record<string, unknown>[]; }>


OptionalKeys<T> = { [K in keyof T]: undefined extends OutputOf<T[K]> ? K : never }[keyof T]

Type Parameter
T extends ToolShape

OutputOf<S> = S extends object ? O : S extends object ? O : never

Type Parameter
S

PromptContributor = (context) => PromptSection[] | Promise<PromptSection[]>

Parameter Type
context PromptContext

PromptSection[] | Promise<PromptSection[]>


ToolParams<T> = { [K in Exclude<keyof T, OptionalKeys<T>>]: OutputOf<T[K]> } & { [K in OptionalKeys<T>]?: OutputOf<T[K]> }

What z.infer<z.ZodObject<T>> gives, computed from _output so it works for both majors.

Type Parameter
T extends ToolShape

ToolParamSchema = { _output: unknown; } | { _zod: { output: unknown; }; }

Accept parameter schemas from either supported zod major through their common output member, without requiring one major’s private schema internals. See docs/decisions/0011-sdk-runtime-invariants.md for the retained rationale.


ToolShape = object

[key: string]: ToolParamSchema

const DEFAULT_RESULT_CHAR_LIMIT: 100000 = 100_000

adaptMcpTools(options): AdaptedMcpTools

Parameter Type
options AdaptMcpToolsOptions

AdaptedMcpTools


buildCliSpec<T, R>(tool): CliToolSpec

Type Parameter
T extends ToolShape
R
Parameter Type
tool ToolDefinition<T, R>

CliToolSpec


buildToolCallback(tool, options?): (params) => Promise<{[key: string]: unknown; }>

Parameter Type
tool AnyToolDefinition
options RegisterToolsOptions

(params) => Promise<{[key: string]: unknown; }>


capText(text, opts?): CappedText

Parameter Type
text string
opts CapOptions

CappedText


capToolResult<T>(result, limit?): T

Type Parameter
T
Parameter Type
result T
limit? number

T


definePrompt<T>(contributor): T

Mark a function as a bag prompt entry and retain its inferred type.

Type Parameter
T extends PromptContributor
Parameter Type
contributor T

T


defineTool<T, R>(definition): ToolDefinition<T, R>

Type Parameter
T extends ToolShape
R
Parameter Type
definition ToolDefinition<T, R>

ToolDefinition<T, R>


formatOutput<R>(result, tool, json): string

Type Parameter
R
Parameter Type
result R
tool ToolDefinition<ToolShape, R>
json boolean

string


getHandlerMap(server): Map<string, ListToolsHandler> | undefined

The SDK’s live protocol-handler map. The sole sanctioned reach-in here; Undefined for a test double with no inner server.

Exported for register-normalize-guard.test.ts, which has to inspect the same map to prove the wrap took effect. Sharing this keeps the assertion in one place rather than repeating the cast at every call site.

Parameter Type
server McpServer

Map<string, ListToolsHandler> | undefined


isMcpResult(value): value is { [key: string]: unknown }

Parameter Type
value unknown

value is { [key: string]: unknown }


mcpResult<T>(response): T

Type Parameter
T extends object
Parameter Type
response T

T


registerTools(server, tools, options?): void

Parameter Type
server McpServer
tools AnyToolDefinition[]
options RegisterToolsOptions

void


resolveParams(spec, positionalValue, options): Record<string, unknown>

Parameter Type
spec CliToolSpec
positionalValue string | undefined
options Record<string, unknown>

Record<string, unknown>


resolveSessionId(context?): string

Resolve the session id preferring the per-request context (set by the shared HTTP MCP server) and falling back to the env var (CLI stdio mode). The shared server has no per-session BARRY_SESSION_ID, so context.sessionId is the only reliable source there.

Parameter Type
context? ToolContext

string


resolveUserPath(filePath): string

Resolve a user-supplied path the way the builtin tools do: ~/~/... expands against HOME, anything else resolves against the process working directory. Shared so path-based policy (scope-guard deny patterns, read-tracking keys) sees the same normalized path the tools actually touch.

Parameter Type
filePath string

string


resultCharLimitFromEnv(): number

number


toolNameToCommand(toolName, namespace): string

Parameter Type
toolName string
namespace string

string


withCredentialGuidance(message): string

Parameter Type
message string

string