@sriramadari/mcp-devkit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +180 -0
- package/dist/chunk-EANYYOGZ.js +437 -0
- package/dist/chunk-EANYYOGZ.js.map +1 -0
- package/dist/cli.cjs +619 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +623 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +409 -0
- package/dist/index.d.ts +409 -0
- package/dist/index.js +181 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connect.ts","../src/schema.ts","../src/client.ts","../src/expect.ts","../src/conformance.ts","../src/mock.ts"],"names":["Client","InMemoryTransport","StdioClientTransport","McpServer"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * connect.ts — establish a live MCP client connection to a target.\n *\n * Two transports, one entry point:\n * - in-process (`InMemoryTransport.createLinkedPair`) for an `McpServer` you\n * constructed in the same test, and\n * - stdio (`StdioClientTransport`) for a server you launch as a child process.\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { InMemoryTransport } from \"@modelcontextprotocol/sdk/inMemory.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { ConnectOptions, ConnectTarget } from \"./types\";\n\nexport interface Connection {\n client: Client;\n /** Tears down the client, the transport, and any spawned child process. */\n close: () => Promise<void>;\n}\n\nexport async function openConnection(\n target: ConnectTarget,\n options: ConnectOptions = {},\n): Promise<Connection> {\n const client = new Client({\n name: options.clientName ?? \"mcp-devkit\",\n version: options.clientVersion ?? \"0.1.0\",\n });\n\n if (\"server\" in target && target.server) {\n const server = typeof target.server === \"function\" ? await target.server() : target.server;\n const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();\n // Connect the server first so it's listening before the client handshakes.\n await server.connect(serverTransport);\n await client.connect(clientTransport);\n return {\n client,\n close: async () => {\n await client.close().catch(() => {});\n await server.close().catch(() => {});\n },\n };\n }\n\n if (\"command\" in target && target.command) {\n const transport = new StdioClientTransport({\n command: target.command,\n args: target.args ?? [],\n env: target.env,\n cwd: target.cwd,\n });\n await client.connect(transport);\n return {\n client,\n // Closing the client closes the transport, which terminates the child.\n close: async () => {\n await client.close().catch(() => {});\n },\n };\n }\n\n throw new Error(\"openConnection: target must provide either `server` or `command`\");\n}\n","/**\n * schema.ts — a tiny, dependency-free JSON Schema validator.\n *\n * This is NOT a spec-complete validator (use ajv for that). It covers the\n * subset MCP tool `inputSchema`s actually use in practice — types, required\n * properties, enums, nested objects/arrays, basic numeric/string bounds, and\n * the combinators — so a test can catch \"I'm calling this tool with the wrong\n * args\" before the call ever leaves the process.\n */\n\nimport type { JsonSchema, JsonSchemaType } from \"./types\";\n\nexport interface ValidationError {\n /** JSON-pointer-ish path to the offending value, e.g. `/items/0/name`. */\n path: string;\n message: string;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n}\n\nconst TYPEOF: Record<string, JsonSchemaType> = {\n string: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n};\n\nfunction typeOf(value: unknown): JsonSchemaType {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n const t = typeof value;\n if (t === \"object\") return \"object\";\n return TYPEOF[t] ?? \"string\";\n}\n\nfunction matchesType(value: unknown, type: JsonSchemaType): boolean {\n switch (type) {\n case \"integer\":\n return typeof value === \"number\" && Number.isInteger(value);\n case \"number\":\n return typeof value === \"number\";\n case \"null\":\n return value === null;\n default:\n return typeOf(value) === type;\n }\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== typeof b || a === null || b === null) return false;\n if (typeof a !== \"object\") return false;\n const ka = Object.keys(a as object);\n const kb = Object.keys(b as object);\n if (ka.length !== kb.length) return false;\n return ka.every((k) =>\n deepEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n );\n}\n\n/**\n * Validate `value` against `schema`. Returns every error found, not just the\n * first — handy for surfacing all the problems with a tool call at once.\n */\nexport function validateAgainstSchema(value: unknown, schema: JsonSchema): ValidationResult {\n const errors: ValidationError[] = [];\n walk(value, schema, \"\", errors);\n return { valid: errors.length === 0, errors };\n}\n\nfunction walk(value: unknown, schema: JsonSchema, path: string, errors: ValidationError[]): void {\n if (!schema || typeof schema !== \"object\") return;\n\n // const / enum\n if (\"const\" in schema && !deepEqual(value, schema.const)) {\n errors.push({ path: path || \"/\", message: `must equal ${JSON.stringify(schema.const)}` });\n }\n if (schema.enum && !schema.enum.some((e) => deepEqual(e, value))) {\n errors.push({ path: path || \"/\", message: `must be one of ${JSON.stringify(schema.enum)}` });\n }\n\n // combinators\n if (schema.allOf) {\n for (const sub of schema.allOf) walk(value, sub, path, errors);\n }\n if (schema.anyOf && !schema.anyOf.some((sub) => validateAgainstSchema(value, sub).valid)) {\n errors.push({ path: path || \"/\", message: \"did not match any schema in anyOf\" });\n }\n if (schema.oneOf) {\n const hits = schema.oneOf.filter((sub) => validateAgainstSchema(value, sub).valid).length;\n if (hits !== 1) {\n errors.push({ path: path || \"/\", message: `must match exactly one schema in oneOf (matched ${hits})` });\n }\n }\n\n // type\n const types = schema.type === undefined ? [] : Array.isArray(schema.type) ? schema.type : [schema.type];\n if (types.length > 0 && !types.some((t) => matchesType(value, t))) {\n errors.push({ path: path || \"/\", message: `expected type ${types.join(\" | \")}, got ${typeOf(value)}` });\n return; // further checks would be noise once the type is wrong\n }\n\n const actual = typeOf(value);\n\n if (actual === \"string\" && typeof value === \"string\") {\n if (schema.minLength !== undefined && value.length < schema.minLength) {\n errors.push({ path: path || \"/\", message: `shorter than minLength ${schema.minLength}` });\n }\n if (schema.maxLength !== undefined && value.length > schema.maxLength) {\n errors.push({ path: path || \"/\", message: `longer than maxLength ${schema.maxLength}` });\n }\n }\n\n if (actual === \"number\" && typeof value === \"number\") {\n if (schema.minimum !== undefined && value < schema.minimum) {\n errors.push({ path: path || \"/\", message: `less than minimum ${schema.minimum}` });\n }\n if (schema.maximum !== undefined && value > schema.maximum) {\n errors.push({ path: path || \"/\", message: `greater than maximum ${schema.maximum}` });\n }\n }\n\n if (actual === \"object\" && value && typeof value === \"object\") {\n const obj = value as Record<string, unknown>;\n for (const key of schema.required ?? []) {\n if (!(key in obj)) {\n errors.push({ path: `${path}/${key}`, message: \"is required\" });\n }\n }\n if (schema.properties) {\n for (const [key, sub] of Object.entries(schema.properties)) {\n if (key in obj) walk(obj[key], sub, `${path}/${key}`, errors);\n }\n }\n if (schema.additionalProperties === false && schema.properties) {\n const allowed = new Set(Object.keys(schema.properties));\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key)) {\n errors.push({ path: `${path}/${key}`, message: \"is not an allowed property\" });\n }\n }\n } else if (schema.additionalProperties && typeof schema.additionalProperties === \"object\") {\n const declared = new Set(Object.keys(schema.properties ?? {}));\n for (const key of Object.keys(obj)) {\n if (!declared.has(key)) {\n walk(obj[key], schema.additionalProperties, `${path}/${key}`, errors);\n }\n }\n }\n }\n\n if (actual === \"array\" && Array.isArray(value)) {\n if (Array.isArray(schema.items)) {\n schema.items.forEach((sub, i) => {\n if (i < value.length) walk(value[i], sub, `${path}/${i}`, errors);\n });\n } else if (schema.items) {\n value.forEach((item, i) => walk(item, schema.items as JsonSchema, `${path}/${i}`, errors));\n }\n }\n}\n","/**\n * client.ts — the TestClient: an ergonomic wrapper over the raw SDK Client.\n *\n * Everything a test reaches for, with the protocol boilerplate removed:\n * - cached `tools()` / `resources()` / `prompts()` listings\n * - `hasTool()`, `tool()` lookups\n * - `call()` that optionally validates args against the tool's declared\n * `inputSchema` *before* sending, so a bad call fails loudly in your test\n * instead of silently in the server\n * - `readResource()` / `getPrompt()` passthroughs\n *\n * Construct one with `createTestClient(target, options)`.\n */\n\nimport type { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { openConnection } from \"./connect\";\nimport { validateAgainstSchema } from \"./schema\";\nimport type {\n ConnectOptions,\n ConnectTarget,\n PromptInfo,\n ResourceInfo,\n ToolInfo,\n ToolResult,\n} from \"./types\";\n\nexport interface CallOptions {\n /**\n * Validate `args` against the tool's `inputSchema` before sending.\n * Default `true`. Throws a descriptive error if the args don't match.\n */\n validate?: boolean;\n /** Per-call timeout in ms (overrides the connection default). */\n timeoutMs?: number;\n}\n\nexport class TestClient {\n /** The underlying SDK client — escape hatch for anything not wrapped here. */\n readonly raw: Client;\n private readonly _close: () => Promise<void>;\n private readonly defaultTimeoutMs: number;\n\n private _tools?: ToolInfo[];\n private _resources?: ResourceInfo[];\n private _prompts?: PromptInfo[];\n\n /** @internal — use {@link createTestClient}. */\n constructor(raw: Client, close: () => Promise<void>, defaultTimeoutMs: number) {\n this.raw = raw;\n this._close = close;\n this.defaultTimeoutMs = defaultTimeoutMs;\n }\n\n // ── server identity / capabilities ─────────────────────────────────────────\n\n serverInfo(): { name: string; version: string } | undefined {\n return this.raw.getServerVersion() as { name: string; version: string } | undefined;\n }\n\n capabilities(): Record<string, unknown> | undefined {\n return this.raw.getServerCapabilities() as Record<string, unknown> | undefined;\n }\n\n // ── tools ───────────────────────────────────────────────────────────────────\n\n /** List the server's tools (cached after the first call — see {@link refresh}). */\n async tools(): Promise<ToolInfo[]> {\n if (!this._tools) {\n const res = await this.raw.listTools();\n this._tools = (res.tools ?? []) as ToolInfo[];\n }\n return this._tools;\n }\n\n async toolNames(): Promise<string[]> {\n return (await this.tools()).map((t) => t.name);\n }\n\n async hasTool(name: string): Promise<boolean> {\n return (await this.tools()).some((t) => t.name === name);\n }\n\n async tool(name: string): Promise<ToolInfo | undefined> {\n return (await this.tools()).find((t) => t.name === name);\n }\n\n /**\n * Call a tool. By default the args are validated against the tool's declared\n * `inputSchema` first; set `{ validate: false }` to send them as-is (e.g. to\n * test how the server handles bad input).\n */\n async call(\n name: string,\n args: Record<string, unknown> = {},\n options: CallOptions = {},\n ): Promise<ToolResult> {\n if (options.validate !== false) {\n const info = await this.tool(name);\n if (info?.inputSchema) {\n const { valid, errors } = validateAgainstSchema(args, info.inputSchema);\n if (!valid) {\n const detail = errors.map((e) => ` ${e.path} ${e.message}`).join(\"\\n\");\n throw new Error(`Arguments for tool \"${name}\" do not match its inputSchema:\\n${detail}`);\n }\n }\n }\n const result = await this.raw.callTool(\n { name, arguments: args },\n undefined,\n { timeout: options.timeoutMs ?? this.defaultTimeoutMs },\n );\n return result as ToolResult;\n }\n\n // ── resources ─────────────────────────────────────────────────────────────\n\n async resources(): Promise<ResourceInfo[]> {\n if (!this._resources) {\n try {\n const res = await this.raw.listResources();\n this._resources = (res.resources ?? []) as ResourceInfo[];\n } catch {\n this._resources = []; // server doesn't advertise the resources capability\n }\n }\n return this._resources;\n }\n\n async readResource(uri: string): Promise<{ contents: Array<{ uri: string; text?: string; blob?: string; mimeType?: string }> }> {\n return (await this.raw.readResource({ uri })) as {\n contents: Array<{ uri: string; text?: string; blob?: string; mimeType?: string }>;\n };\n }\n\n // ── prompts ───────────────────────────────────────────────────────────────\n\n async prompts(): Promise<PromptInfo[]> {\n if (!this._prompts) {\n try {\n const res = await this.raw.listPrompts();\n this._prompts = (res.prompts ?? []) as PromptInfo[];\n } catch {\n this._prompts = [];\n }\n }\n return this._prompts;\n }\n\n async getPrompt(name: string, args: Record<string, unknown> = {}): Promise<unknown> {\n return this.raw.getPrompt({ name, arguments: args as Record<string, string> });\n }\n\n // ── lifecycle ───────────────────────────────────────────────────────────────\n\n /** Drop cached listings so the next `tools()`/`resources()`/`prompts()` re-fetches. */\n refresh(): void {\n this._tools = undefined;\n this._resources = undefined;\n this._prompts = undefined;\n }\n\n /** Liveness check — resolves if the server answers a ping. */\n async ping(): Promise<void> {\n await this.raw.ping();\n }\n\n /** Tear down the connection (and any spawned child process). Idempotent. */\n async close(): Promise<void> {\n await this._close();\n }\n}\n\n/**\n * Open a connection to an MCP server and return a ready-to-use {@link TestClient}.\n *\n * @example In-process (your own server):\n * ```ts\n * const client = await createTestClient({ server: buildMyServer() });\n * const res = await client.call(\"search\", { q: \"mcp\" });\n * await client.close();\n * ```\n *\n * @example Over stdio (any server binary):\n * ```ts\n * const client = await createTestClient({ command: \"node\", args: [\"dist/server.js\"] });\n * ```\n */\nexport async function createTestClient(\n target: ConnectTarget,\n options: ConnectOptions = {},\n): Promise<TestClient> {\n const { client, close } = await openConnection(target, options);\n return new TestClient(client, close, options.timeoutMs ?? 10_000);\n}\n\n/**\n * Run `fn` with a connected client and guarantee it's closed afterwards, even\n * if the test throws. Returns whatever `fn` returns.\n *\n * @example\n * ```ts\n * await withTestClient({ server }, async (client) => {\n * expectToolResult(await client.call(\"ping\")).toSucceed();\n * });\n * ```\n */\nexport async function withTestClient<T>(\n target: ConnectTarget,\n fn: (client: TestClient) => Promise<T>,\n options: ConnectOptions = {},\n): Promise<T> {\n const client = await createTestClient(target, options);\n try {\n return await fn(client);\n } finally {\n await client.close();\n }\n}\n","/**\n * expect.ts — fluent, framework-agnostic assertions for MCP tool results.\n *\n * These throw a plain `Error` on failure (no dependency on vitest/jest/node:test),\n * so they slot into any runner. Every matcher returns `this`, so they chain:\n *\n * ```ts\n * expectToolResult(res)\n * .toSucceed()\n * .toHaveText(/found 3 results/)\n * .toMatchStructured({ count: 3 });\n * ```\n */\n\nimport { validateAgainstSchema } from \"./schema\";\nimport type { ContentBlock, JsonSchema, ToolResult } from \"./types\";\n\nexport class ToolResultAssertion {\n constructor(private readonly result: ToolResult) {\n if (!result || !Array.isArray(result.content)) {\n throw new Error(\n \"expectToolResult: value is not an MCP tool result (missing `content` array)\",\n );\n }\n }\n\n /** The text of all `type: \"text\"` content blocks, joined by newlines. */\n text(): string {\n return this.result.content\n .filter((b): b is ContentBlock & { text: string } => b.type === \"text\" && typeof b.text === \"string\")\n .map((b) => b.text)\n .join(\"\\n\");\n }\n\n /** Parse the joined text content as JSON. Throws if it isn't valid JSON. */\n json<T = unknown>(): T {\n const text = this.text();\n try {\n return JSON.parse(text) as T;\n } catch (e) {\n throw new Error(`expected tool result text to be JSON, but parsing failed: ${(e as Error).message}\\n--- text ---\\n${text}`);\n }\n }\n\n /** The raw result, for assertions the matchers don't cover. */\n raw(): ToolResult {\n return this.result;\n }\n\n // ── success / failure ───────────────────────────────────────────────────────\n\n /** Asserts the tool did NOT report an error (`isError` is not true). */\n toSucceed(): this {\n if (this.result.isError === true) {\n throw new Error(`expected tool result to succeed, but isError=true\\n--- content ---\\n${this.text()}`);\n }\n return this;\n }\n\n /** Asserts the tool reported an error (`isError === true`). */\n toError(): this {\n if (this.result.isError !== true) {\n throw new Error(`expected tool result to be an error (isError=true), but it succeeded\\n--- content ---\\n${this.text()}`);\n }\n return this;\n }\n\n /** Alias for {@link toError}. */\n toFail(): this {\n return this.toError();\n }\n\n // ── content ─────────────────────────────────────────────────────────────────\n\n /** Asserts the joined text content contains a substring, or matches a RegExp. */\n toHaveText(expected: string | RegExp): this {\n const text = this.text();\n const ok = typeof expected === \"string\" ? text.includes(expected) : expected.test(text);\n if (!ok) {\n throw new Error(`expected tool text to ${typeof expected === \"string\" ? `contain \"${expected}\"` : `match ${expected}`}, got:\\n${text}`);\n }\n return this;\n }\n\n /** Asserts there is at least one content block of the given type. */\n toHaveContentType(type: string): this {\n if (!this.result.content.some((b) => b.type === type)) {\n const seen = [...new Set(this.result.content.map((b) => b.type))].join(\", \") || \"(none)\";\n throw new Error(`expected a content block of type \"${type}\", but saw: ${seen}`);\n }\n return this;\n }\n\n /** Asserts the number of content blocks. */\n toHaveContentCount(n: number): this {\n if (this.result.content.length !== n) {\n throw new Error(`expected ${n} content block(s), got ${this.result.content.length}`);\n }\n return this;\n }\n\n /** Asserts at least one content block satisfies the predicate. */\n toSatisfy(predicate: (block: ContentBlock) => boolean, message = \"predicate\"): this {\n if (!this.result.content.some(predicate)) {\n throw new Error(`expected at least one content block to satisfy ${message}`);\n }\n return this;\n }\n\n // ── structured content ──────────────────────────────────────────────────────\n\n /**\n * Asserts `structuredContent` deep-contains the given partial object.\n * (Recursive subset match — extra keys on the actual value are fine.)\n */\n toMatchStructured(expected: Record<string, unknown>): this {\n const actual = this.result.structuredContent;\n const miss = subsetMismatch(actual, expected, \"\");\n if (miss) {\n throw new Error(`structuredContent mismatch at ${miss.path}: ${miss.message}\\n--- actual ---\\n${JSON.stringify(actual, null, 2)}`);\n }\n return this;\n }\n\n /** Asserts `structuredContent` validates against a JSON Schema. */\n toMatchSchema(schema: JsonSchema): this {\n const { valid, errors } = validateAgainstSchema(this.result.structuredContent, schema);\n if (!valid) {\n const detail = errors.map((e) => ` ${e.path} ${e.message}`).join(\"\\n\");\n throw new Error(`structuredContent does not match schema:\\n${detail}`);\n }\n return this;\n }\n}\n\nfunction subsetMismatch(actual: unknown, expected: unknown, path: string): { path: string; message: string } | null {\n if (expected !== null && typeof expected === \"object\" && !Array.isArray(expected)) {\n if (actual === null || typeof actual !== \"object\" || Array.isArray(actual)) {\n return { path: path || \"/\", message: `expected an object, got ${actual === null ? \"null\" : Array.isArray(actual) ? \"array\" : typeof actual}` };\n }\n for (const [k, v] of Object.entries(expected)) {\n const sub = subsetMismatch((actual as Record<string, unknown>)[k], v, `${path}/${k}`);\n if (sub) return sub;\n }\n return null;\n }\n if (Array.isArray(expected)) {\n if (!Array.isArray(actual)) return { path: path || \"/\", message: `expected an array, got ${typeof actual}` };\n if (actual.length !== expected.length) return { path: path || \"/\", message: `expected length ${expected.length}, got ${actual.length}` };\n for (let i = 0; i < expected.length; i++) {\n const sub = subsetMismatch(actual[i], expected[i], `${path}/${i}`);\n if (sub) return sub;\n }\n return null;\n }\n if (actual !== expected) {\n return { path: path || \"/\", message: `expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}` };\n }\n return null;\n}\n\n/** Wrap a tool result in a chainable assertion. */\nexport function expectToolResult(result: ToolResult): ToolResultAssertion {\n return new ToolResultAssertion(result);\n}\n","/**\n * conformance.ts — an automated best-practices checker for MCP servers.\n *\n * Point it at a connected {@link TestClient} and it runs a battery of checks\n * that catch the mistakes that make a server hard for an LLM to use well or\n * brittle in production: missing tool descriptions, malformed input schemas,\n * duplicate or illegally-named tools, a server that crashes on an unknown\n * tool, missing server identity, and so on.\n *\n * Each check yields a {@link CheckResult}; the rolled-up {@link ConformanceReport}\n * tells you pass/fail at a glance and is what the CLI's `check` command prints.\n */\n\nimport type { TestClient } from \"./client\";\nimport type { ToolInfo } from \"./types\";\n\nexport type Severity = \"error\" | \"warning\" | \"info\";\nexport type CheckStatus = \"pass\" | \"fail\" | \"skip\";\n\nexport interface CheckResult {\n id: string;\n title: string;\n severity: Severity;\n status: CheckStatus;\n /** Present when status is `fail` or `skip` — why. */\n detail?: string;\n /** Per-item findings (e.g. which tools are missing a description). */\n findings?: string[];\n}\n\nexport interface ConformanceReport {\n ok: boolean;\n checks: CheckResult[];\n summary: { passed: number; failed: number; warnings: number; skipped: number };\n}\n\nexport interface ConformanceOptions {\n /** Check ids to skip entirely. */\n skip?: string[];\n /**\n * Whether to actually *call* a non-existent tool to verify graceful error\n * handling. Default `true`. Disable if your tools have side effects you'd\n * rather not risk (this only ever calls a random non-existent name, but the\n * escape hatch is here regardless).\n */\n probeUnknownTool?: boolean;\n}\n\n// MCP tool names: keep to a conservative, widely-accepted charset.\nconst TOOL_NAME_RE = /^[a-zA-Z0-9_-]{1,128}$/;\n\ntype Check = {\n id: string;\n title: string;\n severity: Severity;\n run: (ctx: { client: TestClient; tools: ToolInfo[]; options: ConformanceOptions }) => Promise<Omit<CheckResult, \"id\" | \"title\" | \"severity\">>;\n};\n\nconst CHECKS: Check[] = [\n {\n id: \"server-identity\",\n title: \"Server reports a name and version\",\n severity: \"warning\",\n run: async ({ client }) => {\n const info = client.serverInfo();\n if (info?.name && info?.version) return { status: \"pass\" };\n return { status: \"fail\", detail: `server info is ${JSON.stringify(info)}` };\n },\n },\n {\n id: \"tools-listable\",\n title: \"tools/list responds\",\n severity: \"error\",\n run: async ({ tools }) => {\n // If we got here, listing already succeeded (tools are pre-fetched).\n return { status: \"pass\", detail: `${tools.length} tool(s)` };\n },\n },\n {\n id: \"unique-tool-names\",\n title: \"Tool names are unique\",\n severity: \"error\",\n run: async ({ tools }) => {\n const seen = new Set<string>();\n const dupes = new Set<string>();\n for (const t of tools) {\n if (seen.has(t.name)) dupes.add(t.name);\n seen.add(t.name);\n }\n return dupes.size === 0\n ? { status: \"pass\" }\n : { status: \"fail\", detail: \"duplicate tool names\", findings: [...dupes] };\n },\n },\n {\n id: \"valid-tool-names\",\n title: \"Tool names use a safe charset and length\",\n severity: \"error\",\n run: async ({ tools }) => {\n const bad = tools.filter((t) => !TOOL_NAME_RE.test(t.name)).map((t) => t.name);\n return bad.length === 0\n ? { status: \"pass\" }\n : { status: \"fail\", detail: \"names must match /^[a-zA-Z0-9_-]{1,128}$/\", findings: bad };\n },\n },\n {\n id: \"tool-descriptions\",\n title: \"Every tool has a description\",\n severity: \"warning\",\n run: async ({ tools }) => {\n const missing = tools.filter((t) => !t.description || !t.description.trim()).map((t) => t.name);\n return missing.length === 0\n ? { status: \"pass\" }\n : { status: \"fail\", detail: \"an LLM picks tools by their description\", findings: missing };\n },\n },\n {\n id: \"description-quality\",\n title: \"Descriptions are substantive (≥ 12 chars)\",\n severity: \"info\",\n run: async ({ tools }) => {\n const thin = tools\n .filter((t) => t.description && t.description.trim().length > 0 && t.description.trim().length < 12)\n .map((t) => `${t.name} (\"${t.description!.trim()}\")`);\n return thin.length === 0\n ? { status: \"pass\" }\n : { status: \"fail\", detail: \"very short descriptions hurt tool selection\", findings: thin };\n },\n },\n {\n id: \"tool-input-schema\",\n title: \"Every tool declares an object inputSchema\",\n severity: \"warning\",\n run: async ({ tools }) => {\n const bad = tools\n .filter((t) => {\n const s = t.inputSchema;\n return !s || typeof s !== \"object\" || s.type !== \"object\";\n })\n .map((t) => t.name);\n return bad.length === 0\n ? { status: \"pass\" }\n : { status: \"fail\", detail: 'inputSchema should be a JSON Schema with type:\"object\"', findings: bad };\n },\n },\n {\n id: \"required-props-exist\",\n title: \"Every `required` entry names a declared property\",\n severity: \"error\",\n run: async ({ tools }) => {\n const findings: string[] = [];\n for (const t of tools) {\n const s = t.inputSchema;\n if (!s?.required || !s.properties) continue;\n const props = new Set(Object.keys(s.properties));\n for (const r of s.required) {\n if (!props.has(r)) findings.push(`${t.name}: required \"${r}\" has no matching property`);\n }\n }\n return findings.length === 0 ? { status: \"pass\" } : { status: \"fail\", findings };\n },\n },\n {\n id: \"unknown-tool-handled\",\n title: \"Calling an unknown tool fails gracefully (no crash/hang)\",\n severity: \"error\",\n run: async ({ client, options }) => {\n if (options.probeUnknownTool === false) {\n return { status: \"skip\", detail: \"probeUnknownTool disabled\" };\n }\n const phantom = \"__mcp_devkit_nonexistent_tool__\";\n try {\n const res = await client.call(phantom, {}, { validate: false, timeoutMs: 5_000 });\n // Either a protocol error (caught below) or an isError result is fine —\n // both are graceful. A *successful* result for a tool that doesn't exist\n // is the bug.\n return res.isError === true\n ? { status: \"pass\", detail: \"returned isError result\" }\n : { status: \"fail\", detail: \"server returned a success result for a non-existent tool\" };\n } catch {\n // A thrown JSON-RPC error is the expected, graceful outcome.\n return { status: \"pass\", detail: \"rejected with a protocol error\" };\n }\n },\n },\n];\n\n/** Run the full conformance battery against a connected client. */\nexport async function conformanceCheck(\n client: TestClient,\n options: ConformanceOptions = {},\n): Promise<ConformanceReport> {\n const skip = new Set(options.skip ?? []);\n const tools = await client.tools();\n const checks: CheckResult[] = [];\n\n for (const check of CHECKS) {\n if (skip.has(check.id)) {\n checks.push({ id: check.id, title: check.title, severity: check.severity, status: \"skip\", detail: \"skipped by caller\" });\n continue;\n }\n try {\n const outcome = await check.run({ client, tools, options });\n checks.push({ id: check.id, title: check.title, severity: check.severity, ...outcome });\n } catch (e) {\n checks.push({\n id: check.id,\n title: check.title,\n severity: check.severity,\n status: \"fail\",\n detail: `check threw: ${(e as Error).message}`,\n });\n }\n }\n\n const summary = {\n passed: checks.filter((c) => c.status === \"pass\").length,\n failed: checks.filter((c) => c.status === \"fail\").length,\n warnings: checks.filter((c) => c.status === \"fail\" && c.severity === \"warning\").length,\n skipped: checks.filter((c) => c.status === \"skip\").length,\n };\n // The server is \"ok\" only if no *error*-severity check failed.\n const ok = !checks.some((c) => c.status === \"fail\" && c.severity === \"error\");\n\n return { ok, checks, summary };\n}\n\n/** The list of checks the kit runs, for documentation/UIs. */\nexport function listChecks(): Array<{ id: string; title: string; severity: Severity }> {\n return CHECKS.map((c) => ({ id: c.id, title: c.title, severity: c.severity }));\n}\n","/**\n * mock.ts — build throwaway `McpServer` fixtures for tests.\n *\n * `createTestClient({ server })` needs *a* server to talk to. Often that's the\n * real one you're testing — but when you're testing the kit itself, or want a\n * controlled server to assert client behaviour against, `mockServer()` spins\n * one up in a few lines.\n *\n * Tool handlers return either a string (wrapped as a single text block) or a\n * partial tool result. Input schemas are passed straight through to the SDK's\n * `registerTool`, so they accept a Zod raw-shape (e.g. `{ q: z.string() }`) —\n * we never import Zod ourselves, keeping the kit dependency-free at runtime.\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ContentBlock } from \"./types\";\n\nexport type MockToolReturn =\n | string\n | {\n content?: ContentBlock[];\n isError?: boolean;\n structuredContent?: unknown;\n };\n\nexport interface MockToolSpec {\n name: string;\n description?: string;\n title?: string;\n /**\n * A Zod raw-shape describing the arguments, e.g. `{ q: z.string() }`.\n * Passed verbatim to `McpServer.registerTool`. Omit for a zero-arg tool.\n */\n inputSchema?: Record<string, unknown>;\n annotations?: Record<string, unknown>;\n /** Runs when the tool is called. May be async. */\n handler: (args: Record<string, unknown>) => MockToolReturn | Promise<MockToolReturn>;\n}\n\nexport interface MockServerSpec {\n name?: string;\n version?: string;\n tools?: MockToolSpec[];\n}\n\nfunction normalize(ret: MockToolReturn): { content: ContentBlock[]; isError?: boolean; structuredContent?: unknown } {\n if (typeof ret === \"string\") {\n return { content: [{ type: \"text\", text: ret }] };\n }\n return {\n content: ret.content ?? [{ type: \"text\", text: \"\" }],\n isError: ret.isError,\n structuredContent: ret.structuredContent,\n };\n}\n\n/**\n * Build an `McpServer` from a compact spec — ready to hand to\n * `createTestClient({ server })`.\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n * const server = mockServer({\n * name: \"demo\",\n * tools: [{\n * name: \"echo\",\n * description: \"Echo the message back\",\n * inputSchema: { message: z.string() },\n * handler: ({ message }) => `you said: ${message}`,\n * }],\n * });\n * ```\n */\nexport function mockServer(spec: MockServerSpec = {}): McpServer {\n const server = new McpServer(\n { name: spec.name ?? \"mock-server\", version: spec.version ?? \"0.0.0\" },\n { capabilities: { tools: {} } },\n );\n\n for (const tool of spec.tools ?? []) {\n const config: Record<string, unknown> = {};\n if (tool.description) config.description = tool.description;\n if (tool.title) config.title = tool.title;\n if (tool.inputSchema) config.inputSchema = tool.inputSchema;\n if (tool.annotations) config.annotations = tool.annotations;\n\n // The SDK's callback receives parsed args (when inputSchema is set) plus an\n // `extra` we don't need here. We funnel both arg-shapes into our handler.\n const cb = async (argsOrExtra: unknown) => {\n const args = (tool.inputSchema ? (argsOrExtra as Record<string, unknown>) : {}) ?? {};\n return normalize(await tool.handler(args));\n };\n\n // registerTool's overloads are tighter than our pass-through types; the\n // cast is intentional and safe — the SDK validates the config at runtime.\n (server.registerTool as unknown as (n: string, c: unknown, cb: unknown) => unknown)(\n tool.name,\n config,\n cb,\n );\n }\n\n return server;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* types.ts — shared types for mcp-devkit.
|
|
6
|
+
*
|
|
7
|
+
* We intentionally keep our public surface decoupled from the exact shapes the
|
|
8
|
+
* MCP SDK exports (those move between minor versions). Where we touch SDK data
|
|
9
|
+
* we describe only the fields we read, structurally — so the kit keeps working
|
|
10
|
+
* across a range of `@modelcontextprotocol/sdk` versions.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** A single content block returned by a tool / prompt / resource read. */
|
|
14
|
+
interface ContentBlock {
|
|
15
|
+
type: string;
|
|
16
|
+
/** Present on `type: "text"` blocks. */
|
|
17
|
+
text?: string;
|
|
18
|
+
/** Present on `type: "image"` / `"audio"` blocks. */
|
|
19
|
+
data?: string;
|
|
20
|
+
mimeType?: string;
|
|
21
|
+
[k: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
/** The result of a `tools/call`, narrowed to the fields we read. */
|
|
24
|
+
interface ToolResult {
|
|
25
|
+
content: ContentBlock[];
|
|
26
|
+
/** `true` when the tool reported a (non-protocol) execution error. */
|
|
27
|
+
isError?: boolean;
|
|
28
|
+
/** Structured payload, when the tool declares an `outputSchema`. */
|
|
29
|
+
structuredContent?: unknown;
|
|
30
|
+
[k: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** A tool descriptor as returned by `tools/list`. */
|
|
33
|
+
interface ToolInfo {
|
|
34
|
+
name: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
inputSchema?: JsonSchema;
|
|
37
|
+
outputSchema?: JsonSchema;
|
|
38
|
+
annotations?: Record<string, unknown>;
|
|
39
|
+
[k: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
/** A resource descriptor as returned by `resources/list`. */
|
|
42
|
+
interface ResourceInfo {
|
|
43
|
+
uri: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
mimeType?: string;
|
|
47
|
+
[k: string]: unknown;
|
|
48
|
+
}
|
|
49
|
+
/** A prompt descriptor as returned by `prompts/list`. */
|
|
50
|
+
interface PromptInfo {
|
|
51
|
+
name: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
arguments?: Array<{
|
|
54
|
+
name: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
required?: boolean;
|
|
57
|
+
}>;
|
|
58
|
+
[k: string]: unknown;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The minimal subset of JSON Schema we understand for input validation.
|
|
62
|
+
* Tools in the wild use far more, but this covers the cases worth checking
|
|
63
|
+
* before a call leaves your test.
|
|
64
|
+
*/
|
|
65
|
+
interface JsonSchema {
|
|
66
|
+
type?: JsonSchemaType | JsonSchemaType[];
|
|
67
|
+
properties?: Record<string, JsonSchema>;
|
|
68
|
+
items?: JsonSchema | JsonSchema[];
|
|
69
|
+
required?: string[];
|
|
70
|
+
enum?: unknown[];
|
|
71
|
+
const?: unknown;
|
|
72
|
+
anyOf?: JsonSchema[];
|
|
73
|
+
oneOf?: JsonSchema[];
|
|
74
|
+
allOf?: JsonSchema[];
|
|
75
|
+
additionalProperties?: boolean | JsonSchema;
|
|
76
|
+
minimum?: number;
|
|
77
|
+
maximum?: number;
|
|
78
|
+
minLength?: number;
|
|
79
|
+
maxLength?: number;
|
|
80
|
+
[k: string]: unknown;
|
|
81
|
+
}
|
|
82
|
+
type JsonSchemaType = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
|
|
83
|
+
/**
|
|
84
|
+
* What to connect a test client to. Exactly one of `server` | `command` must
|
|
85
|
+
* be provided.
|
|
86
|
+
*
|
|
87
|
+
* - `server`: an already-constructed `McpServer` (or a factory returning one).
|
|
88
|
+
* Wired up over an in-process transport — fast, no child process, ideal for
|
|
89
|
+
* unit tests of your own server.
|
|
90
|
+
* - `command` + `args`: a stdio MCP server launched as a child process — what
|
|
91
|
+
* you reach for in an end-to-end test or when inspecting a third-party
|
|
92
|
+
* server you don't import.
|
|
93
|
+
*/
|
|
94
|
+
type ConnectTarget = {
|
|
95
|
+
server: McpServer | (() => McpServer | Promise<McpServer>);
|
|
96
|
+
command?: never;
|
|
97
|
+
} | {
|
|
98
|
+
command: string;
|
|
99
|
+
args?: string[];
|
|
100
|
+
env?: Record<string, string>;
|
|
101
|
+
cwd?: string;
|
|
102
|
+
server?: never;
|
|
103
|
+
};
|
|
104
|
+
interface ConnectOptions {
|
|
105
|
+
/** Client identity sent in the `initialize` handshake. */
|
|
106
|
+
clientName?: string;
|
|
107
|
+
clientVersion?: string;
|
|
108
|
+
/** Per-request timeout in milliseconds (default 10_000). */
|
|
109
|
+
timeoutMs?: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* client.ts — the TestClient: an ergonomic wrapper over the raw SDK Client.
|
|
114
|
+
*
|
|
115
|
+
* Everything a test reaches for, with the protocol boilerplate removed:
|
|
116
|
+
* - cached `tools()` / `resources()` / `prompts()` listings
|
|
117
|
+
* - `hasTool()`, `tool()` lookups
|
|
118
|
+
* - `call()` that optionally validates args against the tool's declared
|
|
119
|
+
* `inputSchema` *before* sending, so a bad call fails loudly in your test
|
|
120
|
+
* instead of silently in the server
|
|
121
|
+
* - `readResource()` / `getPrompt()` passthroughs
|
|
122
|
+
*
|
|
123
|
+
* Construct one with `createTestClient(target, options)`.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
interface CallOptions {
|
|
127
|
+
/**
|
|
128
|
+
* Validate `args` against the tool's `inputSchema` before sending.
|
|
129
|
+
* Default `true`. Throws a descriptive error if the args don't match.
|
|
130
|
+
*/
|
|
131
|
+
validate?: boolean;
|
|
132
|
+
/** Per-call timeout in ms (overrides the connection default). */
|
|
133
|
+
timeoutMs?: number;
|
|
134
|
+
}
|
|
135
|
+
declare class TestClient {
|
|
136
|
+
/** The underlying SDK client — escape hatch for anything not wrapped here. */
|
|
137
|
+
readonly raw: Client;
|
|
138
|
+
private readonly _close;
|
|
139
|
+
private readonly defaultTimeoutMs;
|
|
140
|
+
private _tools?;
|
|
141
|
+
private _resources?;
|
|
142
|
+
private _prompts?;
|
|
143
|
+
/** @internal — use {@link createTestClient}. */
|
|
144
|
+
constructor(raw: Client, close: () => Promise<void>, defaultTimeoutMs: number);
|
|
145
|
+
serverInfo(): {
|
|
146
|
+
name: string;
|
|
147
|
+
version: string;
|
|
148
|
+
} | undefined;
|
|
149
|
+
capabilities(): Record<string, unknown> | undefined;
|
|
150
|
+
/** List the server's tools (cached after the first call — see {@link refresh}). */
|
|
151
|
+
tools(): Promise<ToolInfo[]>;
|
|
152
|
+
toolNames(): Promise<string[]>;
|
|
153
|
+
hasTool(name: string): Promise<boolean>;
|
|
154
|
+
tool(name: string): Promise<ToolInfo | undefined>;
|
|
155
|
+
/**
|
|
156
|
+
* Call a tool. By default the args are validated against the tool's declared
|
|
157
|
+
* `inputSchema` first; set `{ validate: false }` to send them as-is (e.g. to
|
|
158
|
+
* test how the server handles bad input).
|
|
159
|
+
*/
|
|
160
|
+
call(name: string, args?: Record<string, unknown>, options?: CallOptions): Promise<ToolResult>;
|
|
161
|
+
resources(): Promise<ResourceInfo[]>;
|
|
162
|
+
readResource(uri: string): Promise<{
|
|
163
|
+
contents: Array<{
|
|
164
|
+
uri: string;
|
|
165
|
+
text?: string;
|
|
166
|
+
blob?: string;
|
|
167
|
+
mimeType?: string;
|
|
168
|
+
}>;
|
|
169
|
+
}>;
|
|
170
|
+
prompts(): Promise<PromptInfo[]>;
|
|
171
|
+
getPrompt(name: string, args?: Record<string, unknown>): Promise<unknown>;
|
|
172
|
+
/** Drop cached listings so the next `tools()`/`resources()`/`prompts()` re-fetches. */
|
|
173
|
+
refresh(): void;
|
|
174
|
+
/** Liveness check — resolves if the server answers a ping. */
|
|
175
|
+
ping(): Promise<void>;
|
|
176
|
+
/** Tear down the connection (and any spawned child process). Idempotent. */
|
|
177
|
+
close(): Promise<void>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Open a connection to an MCP server and return a ready-to-use {@link TestClient}.
|
|
181
|
+
*
|
|
182
|
+
* @example In-process (your own server):
|
|
183
|
+
* ```ts
|
|
184
|
+
* const client = await createTestClient({ server: buildMyServer() });
|
|
185
|
+
* const res = await client.call("search", { q: "mcp" });
|
|
186
|
+
* await client.close();
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
189
|
+
* @example Over stdio (any server binary):
|
|
190
|
+
* ```ts
|
|
191
|
+
* const client = await createTestClient({ command: "node", args: ["dist/server.js"] });
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
declare function createTestClient(target: ConnectTarget, options?: ConnectOptions): Promise<TestClient>;
|
|
195
|
+
/**
|
|
196
|
+
* Run `fn` with a connected client and guarantee it's closed afterwards, even
|
|
197
|
+
* if the test throws. Returns whatever `fn` returns.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* await withTestClient({ server }, async (client) => {
|
|
202
|
+
* expectToolResult(await client.call("ping")).toSucceed();
|
|
203
|
+
* });
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
declare function withTestClient<T>(target: ConnectTarget, fn: (client: TestClient) => Promise<T>, options?: ConnectOptions): Promise<T>;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* connect.ts — establish a live MCP client connection to a target.
|
|
210
|
+
*
|
|
211
|
+
* Two transports, one entry point:
|
|
212
|
+
* - in-process (`InMemoryTransport.createLinkedPair`) for an `McpServer` you
|
|
213
|
+
* constructed in the same test, and
|
|
214
|
+
* - stdio (`StdioClientTransport`) for a server you launch as a child process.
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
interface Connection {
|
|
218
|
+
client: Client;
|
|
219
|
+
/** Tears down the client, the transport, and any spawned child process. */
|
|
220
|
+
close: () => Promise<void>;
|
|
221
|
+
}
|
|
222
|
+
declare function openConnection(target: ConnectTarget, options?: ConnectOptions): Promise<Connection>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* expect.ts — fluent, framework-agnostic assertions for MCP tool results.
|
|
226
|
+
*
|
|
227
|
+
* These throw a plain `Error` on failure (no dependency on vitest/jest/node:test),
|
|
228
|
+
* so they slot into any runner. Every matcher returns `this`, so they chain:
|
|
229
|
+
*
|
|
230
|
+
* ```ts
|
|
231
|
+
* expectToolResult(res)
|
|
232
|
+
* .toSucceed()
|
|
233
|
+
* .toHaveText(/found 3 results/)
|
|
234
|
+
* .toMatchStructured({ count: 3 });
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
declare class ToolResultAssertion {
|
|
239
|
+
private readonly result;
|
|
240
|
+
constructor(result: ToolResult);
|
|
241
|
+
/** The text of all `type: "text"` content blocks, joined by newlines. */
|
|
242
|
+
text(): string;
|
|
243
|
+
/** Parse the joined text content as JSON. Throws if it isn't valid JSON. */
|
|
244
|
+
json<T = unknown>(): T;
|
|
245
|
+
/** The raw result, for assertions the matchers don't cover. */
|
|
246
|
+
raw(): ToolResult;
|
|
247
|
+
/** Asserts the tool did NOT report an error (`isError` is not true). */
|
|
248
|
+
toSucceed(): this;
|
|
249
|
+
/** Asserts the tool reported an error (`isError === true`). */
|
|
250
|
+
toError(): this;
|
|
251
|
+
/** Alias for {@link toError}. */
|
|
252
|
+
toFail(): this;
|
|
253
|
+
/** Asserts the joined text content contains a substring, or matches a RegExp. */
|
|
254
|
+
toHaveText(expected: string | RegExp): this;
|
|
255
|
+
/** Asserts there is at least one content block of the given type. */
|
|
256
|
+
toHaveContentType(type: string): this;
|
|
257
|
+
/** Asserts the number of content blocks. */
|
|
258
|
+
toHaveContentCount(n: number): this;
|
|
259
|
+
/** Asserts at least one content block satisfies the predicate. */
|
|
260
|
+
toSatisfy(predicate: (block: ContentBlock) => boolean, message?: string): this;
|
|
261
|
+
/**
|
|
262
|
+
* Asserts `structuredContent` deep-contains the given partial object.
|
|
263
|
+
* (Recursive subset match — extra keys on the actual value are fine.)
|
|
264
|
+
*/
|
|
265
|
+
toMatchStructured(expected: Record<string, unknown>): this;
|
|
266
|
+
/** Asserts `structuredContent` validates against a JSON Schema. */
|
|
267
|
+
toMatchSchema(schema: JsonSchema): this;
|
|
268
|
+
}
|
|
269
|
+
/** Wrap a tool result in a chainable assertion. */
|
|
270
|
+
declare function expectToolResult(result: ToolResult): ToolResultAssertion;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* conformance.ts — an automated best-practices checker for MCP servers.
|
|
274
|
+
*
|
|
275
|
+
* Point it at a connected {@link TestClient} and it runs a battery of checks
|
|
276
|
+
* that catch the mistakes that make a server hard for an LLM to use well or
|
|
277
|
+
* brittle in production: missing tool descriptions, malformed input schemas,
|
|
278
|
+
* duplicate or illegally-named tools, a server that crashes on an unknown
|
|
279
|
+
* tool, missing server identity, and so on.
|
|
280
|
+
*
|
|
281
|
+
* Each check yields a {@link CheckResult}; the rolled-up {@link ConformanceReport}
|
|
282
|
+
* tells you pass/fail at a glance and is what the CLI's `check` command prints.
|
|
283
|
+
*/
|
|
284
|
+
|
|
285
|
+
type Severity = "error" | "warning" | "info";
|
|
286
|
+
type CheckStatus = "pass" | "fail" | "skip";
|
|
287
|
+
interface CheckResult {
|
|
288
|
+
id: string;
|
|
289
|
+
title: string;
|
|
290
|
+
severity: Severity;
|
|
291
|
+
status: CheckStatus;
|
|
292
|
+
/** Present when status is `fail` or `skip` — why. */
|
|
293
|
+
detail?: string;
|
|
294
|
+
/** Per-item findings (e.g. which tools are missing a description). */
|
|
295
|
+
findings?: string[];
|
|
296
|
+
}
|
|
297
|
+
interface ConformanceReport {
|
|
298
|
+
ok: boolean;
|
|
299
|
+
checks: CheckResult[];
|
|
300
|
+
summary: {
|
|
301
|
+
passed: number;
|
|
302
|
+
failed: number;
|
|
303
|
+
warnings: number;
|
|
304
|
+
skipped: number;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
interface ConformanceOptions {
|
|
308
|
+
/** Check ids to skip entirely. */
|
|
309
|
+
skip?: string[];
|
|
310
|
+
/**
|
|
311
|
+
* Whether to actually *call* a non-existent tool to verify graceful error
|
|
312
|
+
* handling. Default `true`. Disable if your tools have side effects you'd
|
|
313
|
+
* rather not risk (this only ever calls a random non-existent name, but the
|
|
314
|
+
* escape hatch is here regardless).
|
|
315
|
+
*/
|
|
316
|
+
probeUnknownTool?: boolean;
|
|
317
|
+
}
|
|
318
|
+
/** Run the full conformance battery against a connected client. */
|
|
319
|
+
declare function conformanceCheck(client: TestClient, options?: ConformanceOptions): Promise<ConformanceReport>;
|
|
320
|
+
/** The list of checks the kit runs, for documentation/UIs. */
|
|
321
|
+
declare function listChecks(): Array<{
|
|
322
|
+
id: string;
|
|
323
|
+
title: string;
|
|
324
|
+
severity: Severity;
|
|
325
|
+
}>;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* schema.ts — a tiny, dependency-free JSON Schema validator.
|
|
329
|
+
*
|
|
330
|
+
* This is NOT a spec-complete validator (use ajv for that). It covers the
|
|
331
|
+
* subset MCP tool `inputSchema`s actually use in practice — types, required
|
|
332
|
+
* properties, enums, nested objects/arrays, basic numeric/string bounds, and
|
|
333
|
+
* the combinators — so a test can catch "I'm calling this tool with the wrong
|
|
334
|
+
* args" before the call ever leaves the process.
|
|
335
|
+
*/
|
|
336
|
+
|
|
337
|
+
interface ValidationError {
|
|
338
|
+
/** JSON-pointer-ish path to the offending value, e.g. `/items/0/name`. */
|
|
339
|
+
path: string;
|
|
340
|
+
message: string;
|
|
341
|
+
}
|
|
342
|
+
interface ValidationResult {
|
|
343
|
+
valid: boolean;
|
|
344
|
+
errors: ValidationError[];
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Validate `value` against `schema`. Returns every error found, not just the
|
|
348
|
+
* first — handy for surfacing all the problems with a tool call at once.
|
|
349
|
+
*/
|
|
350
|
+
declare function validateAgainstSchema(value: unknown, schema: JsonSchema): ValidationResult;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* mock.ts — build throwaway `McpServer` fixtures for tests.
|
|
354
|
+
*
|
|
355
|
+
* `createTestClient({ server })` needs *a* server to talk to. Often that's the
|
|
356
|
+
* real one you're testing — but when you're testing the kit itself, or want a
|
|
357
|
+
* controlled server to assert client behaviour against, `mockServer()` spins
|
|
358
|
+
* one up in a few lines.
|
|
359
|
+
*
|
|
360
|
+
* Tool handlers return either a string (wrapped as a single text block) or a
|
|
361
|
+
* partial tool result. Input schemas are passed straight through to the SDK's
|
|
362
|
+
* `registerTool`, so they accept a Zod raw-shape (e.g. `{ q: z.string() }`) —
|
|
363
|
+
* we never import Zod ourselves, keeping the kit dependency-free at runtime.
|
|
364
|
+
*/
|
|
365
|
+
|
|
366
|
+
type MockToolReturn = string | {
|
|
367
|
+
content?: ContentBlock[];
|
|
368
|
+
isError?: boolean;
|
|
369
|
+
structuredContent?: unknown;
|
|
370
|
+
};
|
|
371
|
+
interface MockToolSpec {
|
|
372
|
+
name: string;
|
|
373
|
+
description?: string;
|
|
374
|
+
title?: string;
|
|
375
|
+
/**
|
|
376
|
+
* A Zod raw-shape describing the arguments, e.g. `{ q: z.string() }`.
|
|
377
|
+
* Passed verbatim to `McpServer.registerTool`. Omit for a zero-arg tool.
|
|
378
|
+
*/
|
|
379
|
+
inputSchema?: Record<string, unknown>;
|
|
380
|
+
annotations?: Record<string, unknown>;
|
|
381
|
+
/** Runs when the tool is called. May be async. */
|
|
382
|
+
handler: (args: Record<string, unknown>) => MockToolReturn | Promise<MockToolReturn>;
|
|
383
|
+
}
|
|
384
|
+
interface MockServerSpec {
|
|
385
|
+
name?: string;
|
|
386
|
+
version?: string;
|
|
387
|
+
tools?: MockToolSpec[];
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Build an `McpServer` from a compact spec — ready to hand to
|
|
391
|
+
* `createTestClient({ server })`.
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```ts
|
|
395
|
+
* import { z } from "zod";
|
|
396
|
+
* const server = mockServer({
|
|
397
|
+
* name: "demo",
|
|
398
|
+
* tools: [{
|
|
399
|
+
* name: "echo",
|
|
400
|
+
* description: "Echo the message back",
|
|
401
|
+
* inputSchema: { message: z.string() },
|
|
402
|
+
* handler: ({ message }) => `you said: ${message}`,
|
|
403
|
+
* }],
|
|
404
|
+
* });
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
declare function mockServer(spec?: MockServerSpec): McpServer;
|
|
408
|
+
|
|
409
|
+
export { type CallOptions, type CheckResult, type CheckStatus, type ConformanceOptions, type ConformanceReport, type ConnectOptions, type ConnectTarget, type Connection, type ContentBlock, type JsonSchema, type JsonSchemaType, type MockServerSpec, type MockToolReturn, type MockToolSpec, type PromptInfo, type ResourceInfo, type Severity, TestClient, type ToolInfo, type ToolResult, ToolResultAssertion, type ValidationError, type ValidationResult, conformanceCheck, createTestClient, expectToolResult, listChecks, mockServer, openConnection, validateAgainstSchema, withTestClient };
|