ccusage
Version:
Usage analysis tool for Claude Code
1,443 lines • 381 kB
JavaScript
import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-Dm8hcn_h.js";
import { ZodFirstPartyTypeKind, ZodOptional, ZodType, arrayType, booleanType, dateSchema, discriminatedUnionType, enumType, literalType, numberType, objectType, optionalType, recordType, stringType, unionType, unknownType } from "./_types-Cr2YEzKm.js";
import { getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-BeaFK_sH.js";
import { name, version } from "./logger-Cke8hliP.js";
import process from "node:process";
const LATEST_PROTOCOL_VERSION = "2025-06-18";
const SUPPORTED_PROTOCOL_VERSIONS = [
LATEST_PROTOCOL_VERSION,
"2025-03-26",
"2024-11-05",
"2024-10-07"
];
const JSONRPC_VERSION = "2.0";
/**
* A progress token, used to associate progress notifications with the original request.
*/
const ProgressTokenSchema = unionType([stringType(), numberType().int()]);
/**
* An opaque token used to represent a cursor for pagination.
*/
const CursorSchema = stringType();
const RequestMetaSchema = objectType({ progressToken: optionalType(ProgressTokenSchema) }).passthrough();
const BaseRequestParamsSchema = objectType({ _meta: optionalType(RequestMetaSchema) }).passthrough();
const RequestSchema = objectType({
method: stringType(),
params: optionalType(BaseRequestParamsSchema)
});
const BaseNotificationParamsSchema = objectType({ _meta: optionalType(objectType({}).passthrough()) }).passthrough();
const NotificationSchema = objectType({
method: stringType(),
params: optionalType(BaseNotificationParamsSchema)
});
const ResultSchema = objectType({ _meta: optionalType(objectType({}).passthrough()) }).passthrough();
/**
* A uniquely identifying ID for a request in JSON-RPC.
*/
const RequestIdSchema = unionType([stringType(), numberType().int()]);
/**
* A request that expects a response.
*/
const JSONRPCRequestSchema = objectType({
jsonrpc: literalType(JSONRPC_VERSION),
id: RequestIdSchema
}).merge(RequestSchema).strict();
const isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).success;
/**
* A notification which does not expect a response.
*/
const JSONRPCNotificationSchema = objectType({ jsonrpc: literalType(JSONRPC_VERSION) }).merge(NotificationSchema).strict();
const isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success;
/**
* A successful (non-error) response to a request.
*/
const JSONRPCResponseSchema = objectType({
jsonrpc: literalType(JSONRPC_VERSION),
id: RequestIdSchema,
result: ResultSchema
}).strict();
const isJSONRPCResponse = (value) => JSONRPCResponseSchema.safeParse(value).success;
/**
* Error codes defined by the JSON-RPC specification.
*/
var ErrorCode;
(function(ErrorCode$1) {
ErrorCode$1[ErrorCode$1["ConnectionClosed"] = -32e3] = "ConnectionClosed";
ErrorCode$1[ErrorCode$1["RequestTimeout"] = -32001] = "RequestTimeout";
ErrorCode$1[ErrorCode$1["ParseError"] = -32700] = "ParseError";
ErrorCode$1[ErrorCode$1["InvalidRequest"] = -32600] = "InvalidRequest";
ErrorCode$1[ErrorCode$1["MethodNotFound"] = -32601] = "MethodNotFound";
ErrorCode$1[ErrorCode$1["InvalidParams"] = -32602] = "InvalidParams";
ErrorCode$1[ErrorCode$1["InternalError"] = -32603] = "InternalError";
})(ErrorCode || (ErrorCode = {}));
/**
* A response to a request that indicates an error occurred.
*/
const JSONRPCErrorSchema = objectType({
jsonrpc: literalType(JSONRPC_VERSION),
id: RequestIdSchema,
error: objectType({
code: numberType().int(),
message: stringType(),
data: optionalType(unknownType())
})
}).strict();
const isJSONRPCError = (value) => JSONRPCErrorSchema.safeParse(value).success;
const JSONRPCMessageSchema = unionType([
JSONRPCRequestSchema,
JSONRPCNotificationSchema,
JSONRPCResponseSchema,
JSONRPCErrorSchema
]);
/**
* A response that indicates success but carries no data.
*/
const EmptyResultSchema = ResultSchema.strict();
/**
* This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
*
* The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
*
* This notification indicates that the result will be unused, so any associated processing SHOULD cease.
*
* A client MUST NOT attempt to cancel its `initialize` request.
*/
const CancelledNotificationSchema = NotificationSchema.extend({
method: literalType("notifications/cancelled"),
params: BaseNotificationParamsSchema.extend({
requestId: RequestIdSchema,
reason: stringType().optional()
})
});
/**
* Base metadata interface for common properties across resources, tools, prompts, and implementations.
*/
const BaseMetadataSchema = objectType({
name: stringType(),
title: optionalType(stringType())
}).passthrough();
/**
* Describes the name and version of an MCP implementation.
*/
const ImplementationSchema = BaseMetadataSchema.extend({ version: stringType() });
/**
* Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
*/
const ClientCapabilitiesSchema = objectType({
experimental: optionalType(objectType({}).passthrough()),
sampling: optionalType(objectType({}).passthrough()),
elicitation: optionalType(objectType({}).passthrough()),
roots: optionalType(objectType({ listChanged: optionalType(booleanType()) }).passthrough())
}).passthrough();
/**
* This request is sent from the client to the server when it first connects, asking it to begin initialization.
*/
const InitializeRequestSchema = RequestSchema.extend({
method: literalType("initialize"),
params: BaseRequestParamsSchema.extend({
protocolVersion: stringType(),
capabilities: ClientCapabilitiesSchema,
clientInfo: ImplementationSchema
})
});
const isInitializeRequest = (value) => InitializeRequestSchema.safeParse(value).success;
/**
* Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.
*/
const ServerCapabilitiesSchema = objectType({
experimental: optionalType(objectType({}).passthrough()),
logging: optionalType(objectType({}).passthrough()),
completions: optionalType(objectType({}).passthrough()),
prompts: optionalType(objectType({ listChanged: optionalType(booleanType()) }).passthrough()),
resources: optionalType(objectType({
subscribe: optionalType(booleanType()),
listChanged: optionalType(booleanType())
}).passthrough()),
tools: optionalType(objectType({ listChanged: optionalType(booleanType()) }).passthrough())
}).passthrough();
/**
* After receiving an initialize request from the client, the server sends this response.
*/
const InitializeResultSchema = ResultSchema.extend({
protocolVersion: stringType(),
capabilities: ServerCapabilitiesSchema,
serverInfo: ImplementationSchema,
instructions: optionalType(stringType())
});
/**
* This notification is sent from the client to the server after initialization has finished.
*/
const InitializedNotificationSchema = NotificationSchema.extend({ method: literalType("notifications/initialized") });
/**
* A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
*/
const PingRequestSchema = RequestSchema.extend({ method: literalType("ping") });
const ProgressSchema = objectType({
progress: numberType(),
total: optionalType(numberType()),
message: optionalType(stringType())
}).passthrough();
/**
* An out-of-band notification used to inform the receiver of a progress update for a long-running request.
*/
const ProgressNotificationSchema = NotificationSchema.extend({
method: literalType("notifications/progress"),
params: BaseNotificationParamsSchema.merge(ProgressSchema).extend({ progressToken: ProgressTokenSchema })
});
const PaginatedRequestSchema = RequestSchema.extend({ params: BaseRequestParamsSchema.extend({ cursor: optionalType(CursorSchema) }).optional() });
const PaginatedResultSchema = ResultSchema.extend({ nextCursor: optionalType(CursorSchema) });
/**
* The contents of a specific resource or sub-resource.
*/
const ResourceContentsSchema = objectType({
uri: stringType(),
mimeType: optionalType(stringType()),
_meta: optionalType(objectType({}).passthrough())
}).passthrough();
const TextResourceContentsSchema = ResourceContentsSchema.extend({ text: stringType() });
const BlobResourceContentsSchema = ResourceContentsSchema.extend({ blob: stringType().base64() });
/**
* A known resource that the server is capable of reading.
*/
const ResourceSchema = BaseMetadataSchema.extend({
uri: stringType(),
description: optionalType(stringType()),
mimeType: optionalType(stringType()),
_meta: optionalType(objectType({}).passthrough())
});
/**
* A template description for resources available on the server.
*/
const ResourceTemplateSchema = BaseMetadataSchema.extend({
uriTemplate: stringType(),
description: optionalType(stringType()),
mimeType: optionalType(stringType()),
_meta: optionalType(objectType({}).passthrough())
});
/**
* Sent from the client to request a list of resources the server has.
*/
const ListResourcesRequestSchema = PaginatedRequestSchema.extend({ method: literalType("resources/list") });
/**
* The server's response to a resources/list request from the client.
*/
const ListResourcesResultSchema = PaginatedResultSchema.extend({ resources: arrayType(ResourceSchema) });
/**
* Sent from the client to request a list of resource templates the server has.
*/
const ListResourceTemplatesRequestSchema = PaginatedRequestSchema.extend({ method: literalType("resources/templates/list") });
/**
* The server's response to a resources/templates/list request from the client.
*/
const ListResourceTemplatesResultSchema = PaginatedResultSchema.extend({ resourceTemplates: arrayType(ResourceTemplateSchema) });
/**
* Sent from the client to the server, to read a specific resource URI.
*/
const ReadResourceRequestSchema = RequestSchema.extend({
method: literalType("resources/read"),
params: BaseRequestParamsSchema.extend({ uri: stringType() })
});
/**
* The server's response to a resources/read request from the client.
*/
const ReadResourceResultSchema = ResultSchema.extend({ contents: arrayType(unionType([TextResourceContentsSchema, BlobResourceContentsSchema])) });
/**
* An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
*/
const ResourceListChangedNotificationSchema = NotificationSchema.extend({ method: literalType("notifications/resources/list_changed") });
/**
* Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.
*/
const SubscribeRequestSchema = RequestSchema.extend({
method: literalType("resources/subscribe"),
params: BaseRequestParamsSchema.extend({ uri: stringType() })
});
/**
* Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.
*/
const UnsubscribeRequestSchema = RequestSchema.extend({
method: literalType("resources/unsubscribe"),
params: BaseRequestParamsSchema.extend({ uri: stringType() })
});
/**
* A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.
*/
const ResourceUpdatedNotificationSchema = NotificationSchema.extend({
method: literalType("notifications/resources/updated"),
params: BaseNotificationParamsSchema.extend({ uri: stringType() })
});
/**
* Describes an argument that a prompt can accept.
*/
const PromptArgumentSchema = objectType({
name: stringType(),
description: optionalType(stringType()),
required: optionalType(booleanType())
}).passthrough();
/**
* A prompt or prompt template that the server offers.
*/
const PromptSchema = BaseMetadataSchema.extend({
description: optionalType(stringType()),
arguments: optionalType(arrayType(PromptArgumentSchema)),
_meta: optionalType(objectType({}).passthrough())
});
/**
* Sent from the client to request a list of prompts and prompt templates the server has.
*/
const ListPromptsRequestSchema = PaginatedRequestSchema.extend({ method: literalType("prompts/list") });
/**
* The server's response to a prompts/list request from the client.
*/
const ListPromptsResultSchema = PaginatedResultSchema.extend({ prompts: arrayType(PromptSchema) });
/**
* Used by the client to get a prompt provided by the server.
*/
const GetPromptRequestSchema = RequestSchema.extend({
method: literalType("prompts/get"),
params: BaseRequestParamsSchema.extend({
name: stringType(),
arguments: optionalType(recordType(stringType()))
})
});
/**
* Text provided to or from an LLM.
*/
const TextContentSchema = objectType({
type: literalType("text"),
text: stringType(),
_meta: optionalType(objectType({}).passthrough())
}).passthrough();
/**
* An image provided to or from an LLM.
*/
const ImageContentSchema = objectType({
type: literalType("image"),
data: stringType().base64(),
mimeType: stringType(),
_meta: optionalType(objectType({}).passthrough())
}).passthrough();
/**
* An Audio provided to or from an LLM.
*/
const AudioContentSchema = objectType({
type: literalType("audio"),
data: stringType().base64(),
mimeType: stringType(),
_meta: optionalType(objectType({}).passthrough())
}).passthrough();
/**
* The contents of a resource, embedded into a prompt or tool call result.
*/
const EmbeddedResourceSchema = objectType({
type: literalType("resource"),
resource: unionType([TextResourceContentsSchema, BlobResourceContentsSchema]),
_meta: optionalType(objectType({}).passthrough())
}).passthrough();
/**
* A resource that the server is capable of reading, included in a prompt or tool call result.
*
* Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.
*/
const ResourceLinkSchema = ResourceSchema.extend({ type: literalType("resource_link") });
/**
* A content block that can be used in prompts and tool results.
*/
const ContentBlockSchema = unionType([
TextContentSchema,
ImageContentSchema,
AudioContentSchema,
ResourceLinkSchema,
EmbeddedResourceSchema
]);
/**
* Describes a message returned as part of a prompt.
*/
const PromptMessageSchema = objectType({
role: enumType(["user", "assistant"]),
content: ContentBlockSchema
}).passthrough();
/**
* The server's response to a prompts/get request from the client.
*/
const GetPromptResultSchema = ResultSchema.extend({
description: optionalType(stringType()),
messages: arrayType(PromptMessageSchema)
});
/**
* An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
*/
const PromptListChangedNotificationSchema = NotificationSchema.extend({ method: literalType("notifications/prompts/list_changed") });
/**
* Additional properties describing a Tool to clients.
*
* NOTE: all properties in ToolAnnotations are **hints**.
* They are not guaranteed to provide a faithful description of
* tool behavior (including descriptive properties like `title`).
*
* Clients should never make tool use decisions based on ToolAnnotations
* received from untrusted servers.
*/
const ToolAnnotationsSchema = objectType({
title: optionalType(stringType()),
readOnlyHint: optionalType(booleanType()),
destructiveHint: optionalType(booleanType()),
idempotentHint: optionalType(booleanType()),
openWorldHint: optionalType(booleanType())
}).passthrough();
/**
* Definition for a tool the client can call.
*/
const ToolSchema = BaseMetadataSchema.extend({
description: optionalType(stringType()),
inputSchema: objectType({
type: literalType("object"),
properties: optionalType(objectType({}).passthrough()),
required: optionalType(arrayType(stringType()))
}).passthrough(),
outputSchema: optionalType(objectType({
type: literalType("object"),
properties: optionalType(objectType({}).passthrough()),
required: optionalType(arrayType(stringType()))
}).passthrough()),
annotations: optionalType(ToolAnnotationsSchema),
_meta: optionalType(objectType({}).passthrough())
});
/**
* Sent from the client to request a list of tools the server has.
*/
const ListToolsRequestSchema = PaginatedRequestSchema.extend({ method: literalType("tools/list") });
/**
* The server's response to a tools/list request from the client.
*/
const ListToolsResultSchema = PaginatedResultSchema.extend({ tools: arrayType(ToolSchema) });
/**
* The server's response to a tool call.
*/
const CallToolResultSchema = ResultSchema.extend({
content: arrayType(ContentBlockSchema).default([]),
structuredContent: objectType({}).passthrough().optional(),
isError: optionalType(booleanType())
});
/**
* CallToolResultSchema extended with backwards compatibility to protocol version 2024-10-07.
*/
const CompatibilityCallToolResultSchema = CallToolResultSchema.or(ResultSchema.extend({ toolResult: unknownType() }));
/**
* Used by the client to invoke a tool provided by the server.
*/
const CallToolRequestSchema = RequestSchema.extend({
method: literalType("tools/call"),
params: BaseRequestParamsSchema.extend({
name: stringType(),
arguments: optionalType(recordType(unknownType()))
})
});
/**
* An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
*/
const ToolListChangedNotificationSchema = NotificationSchema.extend({ method: literalType("notifications/tools/list_changed") });
/**
* The severity of a log message.
*/
const LoggingLevelSchema = enumType([
"debug",
"info",
"notice",
"warning",
"error",
"critical",
"alert",
"emergency"
]);
/**
* A request from the client to the server, to enable or adjust logging.
*/
const SetLevelRequestSchema = RequestSchema.extend({
method: literalType("logging/setLevel"),
params: BaseRequestParamsSchema.extend({ level: LoggingLevelSchema })
});
/**
* Notification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.
*/
const LoggingMessageNotificationSchema = NotificationSchema.extend({
method: literalType("notifications/message"),
params: BaseNotificationParamsSchema.extend({
level: LoggingLevelSchema,
logger: optionalType(stringType()),
data: unknownType()
})
});
/**
* Hints to use for model selection.
*/
const ModelHintSchema = objectType({ name: stringType().optional() }).passthrough();
/**
* The server's preferences for model selection, requested of the client during sampling.
*/
const ModelPreferencesSchema = objectType({
hints: optionalType(arrayType(ModelHintSchema)),
costPriority: optionalType(numberType().min(0).max(1)),
speedPriority: optionalType(numberType().min(0).max(1)),
intelligencePriority: optionalType(numberType().min(0).max(1))
}).passthrough();
/**
* Describes a message issued to or received from an LLM API.
*/
const SamplingMessageSchema = objectType({
role: enumType(["user", "assistant"]),
content: unionType([
TextContentSchema,
ImageContentSchema,
AudioContentSchema
])
}).passthrough();
/**
* A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.
*/
const CreateMessageRequestSchema = RequestSchema.extend({
method: literalType("sampling/createMessage"),
params: BaseRequestParamsSchema.extend({
messages: arrayType(SamplingMessageSchema),
systemPrompt: optionalType(stringType()),
includeContext: optionalType(enumType([
"none",
"thisServer",
"allServers"
])),
temperature: optionalType(numberType()),
maxTokens: numberType().int(),
stopSequences: optionalType(arrayType(stringType())),
metadata: optionalType(objectType({}).passthrough()),
modelPreferences: optionalType(ModelPreferencesSchema)
})
});
/**
* The client's response to a sampling/create_message request from the server. The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop) and decide whether to allow the server to see it.
*/
const CreateMessageResultSchema = ResultSchema.extend({
model: stringType(),
stopReason: optionalType(enumType([
"endTurn",
"stopSequence",
"maxTokens"
]).or(stringType())),
role: enumType(["user", "assistant"]),
content: discriminatedUnionType("type", [
TextContentSchema,
ImageContentSchema,
AudioContentSchema
])
});
/**
* Primitive schema definition for boolean fields.
*/
const BooleanSchemaSchema = objectType({
type: literalType("boolean"),
title: optionalType(stringType()),
description: optionalType(stringType()),
default: optionalType(booleanType())
}).passthrough();
/**
* Primitive schema definition for string fields.
*/
const StringSchemaSchema = objectType({
type: literalType("string"),
title: optionalType(stringType()),
description: optionalType(stringType()),
minLength: optionalType(numberType()),
maxLength: optionalType(numberType()),
format: optionalType(enumType([
"email",
"uri",
"date",
"date-time"
]))
}).passthrough();
/**
* Primitive schema definition for number fields.
*/
const NumberSchemaSchema = objectType({
type: enumType(["number", "integer"]),
title: optionalType(stringType()),
description: optionalType(stringType()),
minimum: optionalType(numberType()),
maximum: optionalType(numberType())
}).passthrough();
/**
* Primitive schema definition for enum fields.
*/
const EnumSchemaSchema = objectType({
type: literalType("string"),
title: optionalType(stringType()),
description: optionalType(stringType()),
enum: arrayType(stringType()),
enumNames: optionalType(arrayType(stringType()))
}).passthrough();
/**
* Union of all primitive schema definitions.
*/
const PrimitiveSchemaDefinitionSchema = unionType([
BooleanSchemaSchema,
StringSchemaSchema,
NumberSchemaSchema,
EnumSchemaSchema
]);
/**
* A request from the server to elicit user input via the client.
* The client should present the message and form fields to the user.
*/
const ElicitRequestSchema = RequestSchema.extend({
method: literalType("elicitation/create"),
params: BaseRequestParamsSchema.extend({
message: stringType(),
requestedSchema: objectType({
type: literalType("object"),
properties: recordType(stringType(), PrimitiveSchemaDefinitionSchema),
required: optionalType(arrayType(stringType()))
}).passthrough()
})
});
/**
* The client's response to an elicitation/create request from the server.
*/
const ElicitResultSchema = ResultSchema.extend({
action: enumType([
"accept",
"reject",
"cancel"
]),
content: optionalType(recordType(stringType(), unknownType()))
});
/**
* A reference to a resource or resource template definition.
*/
const ResourceTemplateReferenceSchema = objectType({
type: literalType("ref/resource"),
uri: stringType()
}).passthrough();
/**
* Identifies a prompt.
*/
const PromptReferenceSchema = objectType({
type: literalType("ref/prompt"),
name: stringType()
}).passthrough();
/**
* A request from the client to the server, to ask for completion options.
*/
const CompleteRequestSchema = RequestSchema.extend({
method: literalType("completion/complete"),
params: BaseRequestParamsSchema.extend({
ref: unionType([PromptReferenceSchema, ResourceTemplateReferenceSchema]),
argument: objectType({
name: stringType(),
value: stringType()
}).passthrough(),
context: optionalType(objectType({ arguments: optionalType(recordType(stringType(), stringType())) }))
})
});
/**
* The server's response to a completion/complete request
*/
const CompleteResultSchema = ResultSchema.extend({ completion: objectType({
values: arrayType(stringType()).max(100),
total: optionalType(numberType().int()),
hasMore: optionalType(booleanType())
}).passthrough() });
/**
* Represents a root directory or file that the server can operate on.
*/
const RootSchema = objectType({
uri: stringType().startsWith("file://"),
name: optionalType(stringType()),
_meta: optionalType(objectType({}).passthrough())
}).passthrough();
/**
* Sent from the server to request a list of root URIs from the client.
*/
const ListRootsRequestSchema = RequestSchema.extend({ method: literalType("roots/list") });
/**
* The client's response to a roots/list request from the server.
*/
const ListRootsResultSchema = ResultSchema.extend({ roots: arrayType(RootSchema) });
/**
* A notification from the client to the server, informing it that the list of roots has changed.
*/
const RootsListChangedNotificationSchema = NotificationSchema.extend({ method: literalType("notifications/roots/list_changed") });
const ClientRequestSchema = unionType([
PingRequestSchema,
InitializeRequestSchema,
CompleteRequestSchema,
SetLevelRequestSchema,
GetPromptRequestSchema,
ListPromptsRequestSchema,
ListResourcesRequestSchema,
ListResourceTemplatesRequestSchema,
ReadResourceRequestSchema,
SubscribeRequestSchema,
UnsubscribeRequestSchema,
CallToolRequestSchema,
ListToolsRequestSchema
]);
const ClientNotificationSchema = unionType([
CancelledNotificationSchema,
ProgressNotificationSchema,
InitializedNotificationSchema,
RootsListChangedNotificationSchema
]);
const ClientResultSchema = unionType([
EmptyResultSchema,
CreateMessageResultSchema,
ElicitResultSchema,
ListRootsResultSchema
]);
const ServerRequestSchema = unionType([
PingRequestSchema,
CreateMessageRequestSchema,
ElicitRequestSchema,
ListRootsRequestSchema
]);
const ServerNotificationSchema = unionType([
CancelledNotificationSchema,
ProgressNotificationSchema,
LoggingMessageNotificationSchema,
ResourceUpdatedNotificationSchema,
ResourceListChangedNotificationSchema,
ToolListChangedNotificationSchema,
PromptListChangedNotificationSchema
]);
const ServerResultSchema = unionType([
EmptyResultSchema,
InitializeResultSchema,
CompleteResultSchema,
GetPromptResultSchema,
ListPromptsResultSchema,
ListResourcesResultSchema,
ListResourceTemplatesResultSchema,
ReadResourceResultSchema,
CallToolResultSchema,
ListToolsResultSchema
]);
var McpError = class extends Error {
constructor(code, message, data) {
super(`MCP error ${code}: ${message}`);
this.code = code;
this.data = data;
this.name = "McpError";
}
};
var HTTPException = class extends Error {
res;
status;
constructor(status = 500, options) {
super(options?.message, { cause: options?.cause });
this.res = options?.res;
this.status = status;
}
getResponse() {
if (this.res) {
const newResponse = new Response(this.res.body, {
status: this.status,
headers: this.res.headers
});
return newResponse;
}
return new Response(this.message, { status: this.status });
}
};
var StreamingApi = class {
writer;
encoder;
writable;
abortSubscribers = [];
responseReadable;
aborted = false;
closed = false;
constructor(writable, _readable) {
this.writable = writable;
this.writer = writable.getWriter();
this.encoder = new TextEncoder();
const reader = _readable.getReader();
this.abortSubscribers.push(async () => {
await reader.cancel();
});
this.responseReadable = new ReadableStream({
async pull(controller) {
const { done, value } = await reader.read();
done ? controller.close() : controller.enqueue(value);
},
cancel: () => {
this.abort();
}
});
}
async write(input) {
try {
if (typeof input === "string") input = this.encoder.encode(input);
await this.writer.write(input);
} catch {}
return this;
}
async writeln(input) {
await this.write(input + "\n");
return this;
}
sleep(ms) {
return new Promise((res) => setTimeout(res, ms));
}
async close() {
try {
await this.writer.close();
} catch {}
this.closed = true;
}
async pipe(body) {
this.writer.releaseLock();
await body.pipeTo(this.writable, { preventClose: true });
this.writer = this.writable.getWriter();
}
onAbort(listener) {
this.abortSubscribers.push(listener);
}
abort() {
if (!this.aborted) {
this.aborted = true;
this.abortSubscribers.forEach((subscriber) => subscriber());
}
}
};
var HtmlEscapedCallbackPhase = {
Stringify: 1,
BeforeStream: 2,
Stream: 3
};
var raw = (value, callbacks) => {
const escapedString = new String(value);
escapedString.isEscaped = true;
escapedString.callbacks = callbacks;
return escapedString;
};
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
if (typeof str === "object" && !(str instanceof String)) {
if (!(str instanceof Promise)) str = str.toString();
if (str instanceof Promise) str = await str;
}
const callbacks = str.callbacks;
if (!callbacks?.length) return Promise.resolve(str);
if (buffer) buffer[0] += str;
else buffer = [str];
const resStr = Promise.all(callbacks.map((c) => c({
phase,
buffer,
context
}))).then((res) => Promise.all(res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))).then(() => buffer[0]));
if (preserveCallbacks) return raw(await resStr, callbacks);
else return resStr;
};
var SSEStreamingApi = class extends StreamingApi {
constructor(writable, readable) {
super(writable, readable);
}
async writeSSE(message) {
const data = await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {});
const dataLines = data.split("\n").map((line) => {
return `data: ${line}`;
}).join("\n");
const sseData = [
message.event && `event: ${message.event}`,
dataLines,
message.id && `id: ${message.id}`,
message.retry && `retry: ${message.retry}`
].filter(Boolean).join("\n") + "\n\n";
await this.write(sseData);
}
};
var GET_MATCH_RESULT = Symbol();
var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
const { all = false, dot = false } = options;
const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
const contentType = headers.get("Content-Type");
if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) return parseFormData(request, {
all,
dot
});
return {};
};
async function parseFormData(request, options) {
const formData = await request.formData();
if (formData) return convertFormDataToBodyData(formData, options);
return {};
}
function convertFormDataToBodyData(formData, options) {
const form = /* @__PURE__ */ Object.create(null);
formData.forEach((value, key) => {
const shouldParseAllValues = options.all || key.endsWith("[]");
if (!shouldParseAllValues) form[key] = value;
else handleParsingAllValues(form, key, value);
});
if (options.dot) Object.entries(form).forEach(([key, value]) => {
const shouldParseDotValues = key.includes(".");
if (shouldParseDotValues) {
handleParsingNestedValues(form, key, value);
delete form[key];
}
});
return form;
}
var handleParsingAllValues = (form, key, value) => {
if (form[key] !== void 0) if (Array.isArray(form[key])) form[key].push(value);
else form[key] = [form[key], value];
else if (!key.endsWith("[]")) form[key] = value;
else form[key] = [value];
};
var handleParsingNestedValues = (form, key, value) => {
let nestedForm = form;
const keys = key.split(".");
keys.forEach((key2, index) => {
if (index === keys.length - 1) nestedForm[key2] = value;
else {
if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) nestedForm[key2] = /* @__PURE__ */ Object.create(null);
nestedForm = nestedForm[key2];
}
});
};
var tryDecode = (str, decoder) => {
try {
return decoder(str);
} catch {
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
try {
return decoder(match);
} catch {
return match;
}
});
}
};
var tryDecodeURI = (str) => tryDecode(str, decodeURI);
var getPath = (request) => {
const url = request.url;
const start = url.indexOf("/", url.charCodeAt(9) === 58 ? 13 : 8);
let i = start;
for (; i < url.length; i++) {
const charCode = url.charCodeAt(i);
if (charCode === 37) {
const queryIndex = url.indexOf("?", i);
const path = url.slice(start, queryIndex === -1 ? void 0 : queryIndex);
return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
} else if (charCode === 63) break;
}
return url.slice(start, i);
};
var getPathNoStrict = (request) => {
const result = getPath(request);
return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
};
var mergePath = (base, sub, ...rest) => {
if (rest.length) sub = mergePath(sub, ...rest);
return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
};
var _decodeURI = (value) => {
if (!/[%+]/.test(value)) return value;
if (value.indexOf("+") !== -1) value = value.replace(/\+/g, " ");
return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value;
};
var _getQueryParam = (url, key, multiple) => {
let encoded;
if (!multiple && key && !/[%+]/.test(key)) {
let keyIndex2 = url.indexOf(`?${key}`, 8);
if (keyIndex2 === -1) keyIndex2 = url.indexOf(`&${key}`, 8);
while (keyIndex2 !== -1) {
const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
if (trailingKeyCode === 61) {
const valueIndex = keyIndex2 + key.length + 2;
const endIndex = url.indexOf("&", valueIndex);
return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
} else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) return "";
keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
}
encoded = /[%+]/.test(url);
if (!encoded) return void 0;
}
const results = {};
encoded ??= /[%+]/.test(url);
let keyIndex = url.indexOf("?", 8);
while (keyIndex !== -1) {
const nextKeyIndex = url.indexOf("&", keyIndex + 1);
let valueIndex = url.indexOf("=", keyIndex);
if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) valueIndex = -1;
let name$1 = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex);
if (encoded) name$1 = _decodeURI(name$1);
keyIndex = nextKeyIndex;
if (name$1 === "") continue;
let value;
if (valueIndex === -1) value = "";
else {
value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
if (encoded) value = _decodeURI(value);
}
if (multiple) {
if (!(results[name$1] && Array.isArray(results[name$1]))) results[name$1] = [];
results[name$1].push(value);
} else results[name$1] ??= value;
}
return key ? results[key] : results;
};
var getQueryParam = _getQueryParam;
var getQueryParams = (url, key) => {
return _getQueryParam(url, key, true);
};
var decodeURIComponent_ = decodeURIComponent;
var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
var HonoRequest = class {
raw;
#validatedData;
#matchResult;
routeIndex = 0;
path;
bodyCache = {};
constructor(request, path = "/", matchResult = [[]]) {
this.raw = request;
this.path = path;
this.#matchResult = matchResult;
this.#validatedData = {};
}
param(key) {
return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
}
#getDecodedParam(key) {
const paramKey = this.#matchResult[0][this.routeIndex][1][key];
const param = this.#getParamValue(paramKey);
return param ? /\%/.test(param) ? tryDecodeURIComponent(param) : param : void 0;
}
#getAllDecodedParams() {
const decoded = {};
const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]);
for (const key of keys) {
const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
if (value && typeof value === "string") decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value;
}
return decoded;
}
#getParamValue(paramKey) {
return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey;
}
query(key) {
return getQueryParam(this.url, key);
}
queries(key) {
return getQueryParams(this.url, key);
}
header(name$1) {
if (name$1) return this.raw.headers.get(name$1) ?? void 0;
const headerData = {};
this.raw.headers.forEach((value, key) => {
headerData[key] = value;
});
return headerData;
}
async parseBody(options) {
return this.bodyCache.parsedBody ??= await parseBody(this, options);
}
#cachedBody = (key) => {
const { bodyCache, raw: raw$1 } = this;
const cachedBody = bodyCache[key];
if (cachedBody) return cachedBody;
const anyCachedKey = Object.keys(bodyCache)[0];
if (anyCachedKey) return bodyCache[anyCachedKey].then((body) => {
if (anyCachedKey === "json") body = JSON.stringify(body);
return new Response(body)[key]();
});
return bodyCache[key] = raw$1[key]();
};
json() {
return this.#cachedBody("json");
}
text() {
return this.#cachedBody("text");
}
arrayBuffer() {
return this.#cachedBody("arrayBuffer");
}
blob() {
return this.#cachedBody("blob");
}
formData() {
return this.#cachedBody("formData");
}
addValidatedData(target, data) {
this.#validatedData[target] = data;
}
valid(target) {
return this.#validatedData[target];
}
get url() {
return this.raw.url;
}
get method() {
return this.raw.method;
}
get [GET_MATCH_RESULT]() {
return this.#matchResult;
}
get matchedRoutes() {
return this.#matchResult[0].map(([[, route]]) => route);
}
get routePath() {
return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
}
};
var TEXT_PLAIN = "text/plain; charset=UTF-8";
var setDefaultContentType = (contentType, headers) => {
return {
"Content-Type": contentType,
...headers
};
};
var Context = class {
#rawRequest;
#req;
env = {};
#var;
finalized = false;
error;
#status;
#executionCtx;
#res;
#layout;
#renderer;
#notFoundHandler;
#preparedHeaders;
#matchResult;
#path;
constructor(req, options) {
this.#rawRequest = req;
if (options) {
this.#executionCtx = options.executionCtx;
this.env = options.env;
this.#notFoundHandler = options.notFoundHandler;
this.#path = options.path;
this.#matchResult = options.matchResult;
}
}
get req() {
this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
return this.#req;
}
get event() {
if (this.#executionCtx && "respondWith" in this.#executionCtx) return this.#executionCtx;
else throw Error("This context has no FetchEvent");
}
get executionCtx() {
if (this.#executionCtx) return this.#executionCtx;
else throw Error("This context has no ExecutionContext");
}
get res() {
return this.#res ||= new Response(null, { headers: this.#preparedHeaders ??= new Headers() });
}
set res(_res) {
if (this.#res && _res) {
_res = new Response(_res.body, _res);
for (const [k, v] of this.#res.headers.entries()) {
if (k === "content-type") continue;
if (k === "set-cookie") {
const cookies = this.#res.headers.getSetCookie();
_res.headers.delete("set-cookie");
for (const cookie of cookies) _res.headers.append("set-cookie", cookie);
} else _res.headers.set(k, v);
}
}
this.#res = _res;
this.finalized = true;
}
render = (...args) => {
this.#renderer ??= (content) => this.html(content);
return this.#renderer(...args);
};
setLayout = (layout) => this.#layout = layout;
getLayout = () => this.#layout;
setRenderer = (renderer) => {
this.#renderer = renderer;
};
header = (name$1, value, options) => {
if (this.finalized) this.#res = new Response(this.#res.body, this.#res);
const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
if (value === void 0) headers.delete(name$1);
else if (options?.append) headers.append(name$1, value);
else headers.set(name$1, value);
};
status = (status) => {
this.#status = status;
};
set = (key, value) => {
this.#var ??= /* @__PURE__ */ new Map();
this.#var.set(key, value);
};
get = (key) => {
return this.#var ? this.#var.get(key) : void 0;
};
get var() {
if (!this.#var) return {};
return Object.fromEntries(this.#var);
}
#newResponse(data, arg, headers) {
const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers();
if (typeof arg === "object" && "headers" in arg) {
const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers);
for (const [key, value] of argHeaders) if (key.toLowerCase() === "set-cookie") responseHeaders.append(key, value);
else responseHeaders.set(key, value);
}
if (headers) for (const [k, v] of Object.entries(headers)) if (typeof v === "string") responseHeaders.set(k, v);
else {
responseHeaders.delete(k);
for (const v2 of v) responseHeaders.append(k, v2);
}
const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
return new Response(data, {
status,
headers: responseHeaders
});
}
newResponse = (...args) => this.#newResponse(...args);
body = (data, arg, headers) => this.#newResponse(data, arg, headers);
text = (text, arg, headers) => {
return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(text, arg, setDefaultContentType(TEXT_PLAIN, headers));
};
json = (object, arg, headers) => {
return this.#newResponse(JSON.stringify(object), arg, setDefaultContentType("application/json", headers));
};
html = (html, arg, headers) => {
const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
};
redirect = (location, status) => {
this.header("Location", String(location));
return this.newResponse(null, status ?? 302);
};
notFound = () => {
this.#notFoundHandler ??= () => new Response();
return this.#notFoundHandler(this);
};
};
var isOldBunVersion = () => {
const version$1 = typeof Bun !== "undefined" ? Bun.version : void 0;
if (version$1 === void 0) return false;
const result = version$1.startsWith("1.1") || version$1.startsWith("1.0") || version$1.startsWith("0.");
isOldBunVersion = () => result;
return result;
};
var run = async (stream, cb, onError) => {
try {
await cb(stream);
} catch (e) {
if (e instanceof Error && onError) {
await onError(e, stream);
await stream.writeSSE({
event: "error",
data: e.message
});
} else console.error(e);
}
};
var contextStash = /* @__PURE__ */ new WeakMap();
var streamSSE = (c, cb, onError) => {
const { readable, writable } = new TransformStream();
const stream = new SSEStreamingApi(writable, readable);
if (isOldBunVersion()) c.req.raw.signal.addEventListener("abort", () => {
if (!stream.closed) stream.abort();
});
contextStash.set(stream.responseReadable, c);
c.header("Transfer-Encoding", "chunked");
c.header("Content-Type", "text/event-stream");
c.header("Cache-Control", "no-cache");
c.header("Connection", "keep-alive");
run(stream, cb, onError);
return c.newResponse(stream.responseReadable);
};
var StreamableHTTPTransport = class {
#started = false;
#initialized = false;
#onsessioninitialized;
#sessionIdGenerator;
#eventStore;
#enableJsonResponse = false;
#standaloneSseStreamId = "_GET_stream";
#streamMapping = /* @__PURE__ */ new Map();
#requestToStreamMapping = /* @__PURE__ */ new Map();
#requestResponseMap = /* @__PURE__ */ new Map();
sessionId;
onclose;
onerror;
onmessage;
constructor(options) {
this.#sessionIdGenerator = options?.sessionIdGenerator;
this.#enableJsonResponse = options?.enableJsonResponse ?? false;
this.#eventStore = options?.eventStore;
this.#onsessioninitialized = options?.onsessioninitialized;
}
/**
* Starts the transport. This is required by the Transport interface but is a no-op
* for the Streamable HTTP transport as connections are managed per-request.
*/
async start() {
if (this.#started) throw new Error("Transport already started");
this.#started = true;
}
/**
* Handles an incoming HTTP request, whether GET or POST
*/
async handleRequest(ctx, parsedBody) {
switch (ctx.req.method) {
case "GET": return this.handleGetRequest(ctx);
case "POST": return this.handlePostRequest(ctx, parsedBody);
case "DELETE": return this.handleDeleteRequest(ctx);
default: return this.handleUnsupportedRequest(ctx);
}
}
/**
* Handles GET requests for SSE stream
*/
async handleGetRequest(ctx) {
try {
const acceptHeader = ctx.req.header("Accept");
if (!acceptHeader?.includes("text/event-stream")) throw new HTTPException(406, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32e3,
message: "Not Acceptable: Client must accept text/event-stream"
},
id: null
}) });
this.validateSession(ctx);
if (this.sessionId !== void 0) ctx.header("mcp-session-id", this.sessionId);
let streamId = this.#standaloneSseStreamId;
if (this.#eventStore) {
const lastEventId = ctx.req.header("last-event-id");
if (lastEventId) streamId = (stream) => this.#eventStore.replayEventsAfter(lastEventId, { send: async (eventId, message) => {
try {
await stream.writeSSE({
id: eventId,
event: "message",
data: JSON.stringify(message)
});
} catch {
this.onerror?.(new Error("Failed replay events"));
throw new HTTPException(500, { message: "Failed replay events" });
}
} });
}
if (typeof streamId === "string" && this.#streamMapping.get(streamId) !== void 0) throw new HTTPException(409, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32e3,
message: "Conflict: Only one SSE stream is allowed per session"
},
id: null
}) });
return streamSSE(ctx, async (stream) => {
const resolvedStreamId = typeof streamId === "string" ? streamId : await streamId(stream);
this.#streamMapping.set(resolvedStreamId, {
ctx,
stream
});
const keepAlive = setInterval(() => {
if (!stream.closed) stream.writeSSE({
data: "",
event: "ping"
}).catch(() => clearInterval(keepAlive));
}, 3e4);
stream.onAbort(() => {
this.#streamMapping.delete(resolvedStreamId);
clearInterval(keepAlive);
});
});
} catch (error) {
if (error instanceof HTTPException) throw error;
this.onerror?.(error);
throw new HTTPException(400, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32700,
message: "Parse error",
data: String(error)
},
id: null
}) });
}
}
/**
* Handles POST requests containing JSON-RPC messages
*/
async handlePostRequest(ctx, parsedBody) {
try {
const acceptHeader = ctx.req.header("Accept");
if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) throw new HTTPException(406, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32e3,
message: "Not Acceptable: Client must accept both application/json and text/event-stream"
},
id: null
}) });
const ct = ctx.req.header("Content-Type");
if (!ct?.includes("application/json")) throw new HTTPException(415, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32e3,
message: "Unsupported Media Type: Content-Type must be application/json"
},
id: null
}) });
const authInfo = ctx.get("auth");
let rawMessage = parsedBody;
if (rawMessage === void 0) rawMessage = await ctx.req.json();
let messages;
if (Array.isArray(rawMessage)) messages = rawMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
else messages = [JSONRPCMessageSchema.parse(rawMessage)];
const isInitializationRequest = messages.some(isInitializeRequest);
if (isInitializationRequest) {
if (this.#initialized && this.sessionId !== void 0) throw new HTTPException(400, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32600,
message: "Invalid Request: Server already initialized"
},
id: null
}) });
if (messages.length > 1) throw new HTTPException(400, { res: Response.json({
jsonrpc: "2.0",
error: {
code: -32600,
message: "Invalid Request: Only one initialization request is allowed"
},
id: null
}) });
this.sessionId = this.#sessionIdGenerator?.();
this.#initialized = true;
if (this.sessionId && this.#onsessioninitialized) this.#onsessioninitialized(this.sessionId);
}
if (!isInitializationRequest) this.validateSession(ctx);
const hasRequests = messages.some(isJSONRPCRequest);
if (!hasRequests) {
for (const message of messages) this.onmessage?.(message, { authInfo });
return ctx.body(null, 202);
}
if (hasRequests) {
const streamId = crypto.randomUUID();
if (!this.#enableJsonResponse && this.sessionId !== void 0) ctx.header("mcp-session-id", this.sessionId);
if (this.#enableJsonResponse) {
const result = await new Promise((resolve$4) => {
for (const message of messages) if (isJSONRPCRequest(message)) {
this.#streamMapping.set(streamId, { ctx: {
header: ctx.header,
json: resolve$4
} });
this.#requestToStreamMapping.set(message.id, streamId);
}
for (const message of messages) this.onmessage?.(message, { authInfo });
});
return ctx.json(result);
}
return streamSSE(ctx, async (stream) => {
for (const message of messages) if (isJSONR