Merge commit '70396085b141370ce32de1be4e225b4384eaf46d' into HEAD
# Conflicts: # .agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml # .agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml # .agents/notes/implemented/feature/2026-07-22-web-multimodal-image-input-and-durable-attachments.i18n.yaml # .agents/notes/implemented/feature/2026-07-22-web-multimodal-image-input-and-durable-attachments.md # .agents/notes/implemented/feature/2026-07-22-web-multimodal-image-input-and-durable-attachments.zh.md # .agents/notes/implemented/simplification/2026-07-23-acp-automation-only-protocol.i18n.yaml # docs/config-catalog.i18n.yaml # docs/module-graph.i18n.yaml # docs/module-graph.md # docs/module-graph.zh.md # docs/tool-catalog.i18n.yaml # docs/tool-catalog.md # docs/tool-catalog.zh.md # examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json # examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json # examples/acp-agent/tests/snapshots/code-mode-turn/tool-schemas.expected.json # packages/core/tools/README.i18n.yaml # packages/core/tools/README.zh.md # packages/core/tools/src/code-mode.ts # packages/host/apiproxy/tests/api-proxy-models.spec.ts # packages/host/plugin-inventory/tests/inventory.spec.ts # packages/mcp/mcp-client/tests/mcp-client.e2e.ts # packages/mcp/mcp-client/tests/mcp-client.spec.ts # packages/self-modification/tool-cordis/src/api-catalog.ts # packages/test-support/acp-snapshot/README.i18n.yaml # pnpm-lock.yaml
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@deepseek-ai/dsh-mcp-client",
|
||||
"description": "MCP client bridge: connects to MCP servers and registers their tools on ctx.tools",
|
||||
"version": "0.0.1-rc.2",
|
||||
"version": "0.1.0-rc.6",
|
||||
"publishConfig": {
|
||||
"access": "restricted"
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,7 +30,7 @@
|
||||
"lib/invariant.js",
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Tool bridge: discovers MCP tools, registers them on the harness ToolRegistry
|
||||
* Tool bridge: discovers MCP tools, registers them on the harness ToolRuntime
|
||||
* under deterministic server-qualified public names, and handles re-sync when
|
||||
* the server's tool list changes.
|
||||
*
|
||||
@@ -106,7 +106,7 @@ function callToolUncached(
|
||||
*
|
||||
* @param serverName - Stable local namespace from plugin config.
|
||||
* @param rawName - The MCP server's own tool name.
|
||||
* @returns The globally unique, model-facing ToolRegistry name.
|
||||
* @returns The globally unique, model-facing ToolRuntime name.
|
||||
*/
|
||||
export function publicToolName(serverName: string, rawName: string): string {
|
||||
const joined = `mcp__${serverName}__${rawName}`
|
||||
@@ -117,7 +117,7 @@ export function publicToolName(serverName: string, rawName: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the MCP server's tool list into the harness ToolRegistry.
|
||||
* Sync the MCP server's tool list into the harness ToolRuntime.
|
||||
*
|
||||
* Two phases keep the swap safe:
|
||||
*
|
||||
@@ -207,7 +207,7 @@ interface McpContentBlock {
|
||||
uri?: string
|
||||
}
|
||||
|
||||
/** Async rich projection staged for one exact ToolRegistry execution. */
|
||||
/** Async rich projection staged for one exact ToolRuntime execution. */
|
||||
interface PreparedProjection {
|
||||
/** Canonical MCP value returned by execute before registry materialization. */
|
||||
value: McpResult
|
||||
@@ -239,7 +239,7 @@ function supportedOutputSchema(candidate: unknown): JsonSchemaNode | undefined {
|
||||
* @param structuredSchema - supported structured-output schema, when advertised.
|
||||
* @param taskRequired - whether this MCP tool requires unsupported task execution.
|
||||
* @param opts - bridge timeout and namespace options.
|
||||
* @returns a complete ToolRegistry definition.
|
||||
* @returns a complete ToolRuntime definition.
|
||||
*/
|
||||
function createDefinition(
|
||||
client: Client,
|
||||
@@ -298,7 +298,7 @@ function createOutput(rawName: string, structuredSchema: JsonSchemaNode | undefi
|
||||
* per-page schema cache from pre-validating a different contract.
|
||||
*
|
||||
* When the MCP server returns `isError: true`, the executor throws so that
|
||||
* the ToolRegistry's catch path produces an `isError` result for the model.
|
||||
* the ToolRuntime's catch path produces an `isError` result for the model.
|
||||
*/
|
||||
function createExecutor(
|
||||
client: Client,
|
||||
@@ -340,7 +340,7 @@ function createExecutor(
|
||||
const content = result.content as unknown as JsonValue[]
|
||||
const text = extractText(content, rawName)
|
||||
|
||||
// MCP isError → throw so ToolRegistry produces an isError result for the model.
|
||||
// MCP isError → throw so ToolRuntime produces an isError result for the model.
|
||||
if (result.isError === true) {
|
||||
throw new Error(text)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry from '@deepseek-ai/dsh-tools'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import type { Config } from '@deepseek-ai/dsh-mcp-client'
|
||||
|
||||
// ---- Mock MCP SDK ----
|
||||
@@ -61,7 +61,7 @@ import { apply, name, inject, Config as ConfigSchema } from '@deepseek-ai/dsh-mc
|
||||
async function mountRegistry(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ describe('apply (plugin lifecycle)', () => {
|
||||
it('releases the serverName reservation on dispose', async () => {
|
||||
const first = new Context()
|
||||
await first.plugin(SystemPrompt)
|
||||
await first.plugin(ToolRegistry)
|
||||
await first.plugin(ToolRuntime)
|
||||
await apply(first, stdioConfig)
|
||||
|
||||
await first.fiber.dispose()
|
||||
@@ -221,7 +221,7 @@ describe('apply (plugin lifecycle)', () => {
|
||||
// and the disposed instance no longer holds the reservation on its root.
|
||||
const second = new Context()
|
||||
await second.plugin(SystemPrompt)
|
||||
await second.plugin(ToolRegistry)
|
||||
await second.plugin(ToolRuntime)
|
||||
await expect(apply(second, stdioConfig)).resolves.toBeUndefined()
|
||||
await second.fiber.dispose()
|
||||
})
|
||||
|
||||
@@ -21,8 +21,8 @@ import { z } from 'zod'
|
||||
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'
|
||||
import LocalAttachmentStore from '@deepseek-ai/dsh-attachment-local'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry from '@deepseek-ai/dsh-tools'
|
||||
import { CallId, LlmAdapter, LlmService } from '@deepseek-ai/dsh-llm'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import { CallId, LlmAdapter, LlmRuntime } from '@deepseek-ai/dsh-llm'
|
||||
import type { GenerateOptions, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import { apply } from '@deepseek-ai/dsh-mcp-client/src/index.ts'
|
||||
import { publicToolName } from '@deepseek-ai/dsh-mcp-client/src/tools.ts'
|
||||
@@ -41,7 +41,7 @@ const localBin = join(packageDir, 'node_modules', '.bin')
|
||||
async function mountRegistry(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class ImageAdapter extends LlmAdapter {
|
||||
async function mountImageRegistry(dshHome: string): Promise<Context> {
|
||||
const ctx = await mountRegistry()
|
||||
await ctx.plugin(LocalAttachmentStore, { dshHome })
|
||||
await ctx.plugin(LlmService)
|
||||
await ctx.plugin(LlmRuntime)
|
||||
ctx.llm.registerAdapter(['visual'], new ImageAdapter())
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import AttachmentStore, { AttachmentError, AttachmentId } from '@deepseek-ai/dsh-attachment'
|
||||
import type { ImageAttachmentLimits, ImageAttachmentRef, SaveImageAttachment, StoredImageAttachment } from '@deepseek-ai/dsh-attachment'
|
||||
import { CallId, LlmAdapter, LlmService } from '@deepseek-ai/dsh-llm'
|
||||
import { CallId, LlmAdapter, LlmRuntime } from '@deepseek-ai/dsh-llm'
|
||||
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
||||
import type { GenerateOptions, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry, { type JsonValue } from '@deepseek-ai/dsh-tools'
|
||||
import ToolRuntime, { type JsonValue } from '@deepseek-ai/dsh-tools'
|
||||
import type { PostToolDecision } from '@deepseek-ai/dsh-tools'
|
||||
import { publicToolName, syncTools, type ToolBridgeOptions } from '@deepseek-ai/dsh-mcp-client/src/tools.ts'
|
||||
import { createTransport } from '@deepseek-ai/dsh-mcp-client/src/transport.ts'
|
||||
@@ -64,7 +64,7 @@ function createMockClient(tools: MockTool[], callResult: MockCallResult = { cont
|
||||
async function mountRegistry(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ class ImageCatalogAdapter extends LlmAdapter {
|
||||
async function mountRichRegistry(): Promise<{ ctx: Context; attachments: RecordingAttachmentStore }> {
|
||||
const ctx = await mountRegistry()
|
||||
await ctx.plugin(RecordingAttachmentStore)
|
||||
await ctx.plugin(LlmService)
|
||||
await ctx.plugin(LlmRuntime)
|
||||
ctx.llm.registerAdapter(['visual'], new ImageCatalogAdapter())
|
||||
return { ctx, attachments: ctx.attachments as RecordingAttachmentStore }
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry from '@deepseek-ai/dsh-tools'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import type { Config } from '@deepseek-ai/dsh-mcp-client'
|
||||
|
||||
@@ -68,7 +68,7 @@ const testToolSignal = new AbortController().signal
|
||||
async function mountRegistry(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
return ctx
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"path": "../../subprocess/subprocess"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
"path": "../../runtime-diagnostics/invariants"
|
||||
},
|
||||
{
|
||||
"path": "../../util/timeout"
|
||||
|
||||
Reference in New Issue
Block a user