mirror of
https://github.com/hansjone/dsh-search-mcp.git
synced 2026-10-11 05:40:46 +08:00
Migrate search-mcp to @modelcontextprotocol/client for Desktop 0.2.
Replace the removed monolith SDK import so link/Desktop hosts can resolve MCP from the 0.2 package graph instead of failing import with MODULE_NOT_FOUND. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9d7de03933
commit
229a36d5f3
5 changed files with 99 additions and 1062 deletions
11
README.md
11
README.md
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
用搜索类 MCP 服务器完整替代 DeepSeek Harness(DSH)内置网页搜索的独立插件。
|
||||
|
||||
> 当前兼容基线:DeepSeek Harness `0.1.1-rc.2`,Node.js 20 或更高版本。
|
||||
> 当前兼容基线:DeepSeek Harness `>=0.2.0-rc.2`(Desktop / Web),Node.js 20 或更高版本。
|
||||
> MCP 传输使用 DSH 0.2 提供的 `@modelcontextprotocol/client`(不再依赖已从 Desktop 移除的 monolith `@modelcontextprotocol/sdk`)。
|
||||
|
||||
## 功能
|
||||
|
||||
|
|
@ -17,14 +18,14 @@
|
|||
## 安装
|
||||
|
||||
```powershell
|
||||
git clone https://github.com/gxpppp/dsh-search-mcp.git
|
||||
git clone https://github.com/hansjone/dsh-search-mcp.git
|
||||
cd dsh-search-mcp
|
||||
npm install
|
||||
dsh plugin --profile web add link:<dsh-search-mcp 的绝对路径>
|
||||
dsh web
|
||||
dsh plugin --profile desktop add link:<dsh-search-mcp 的绝对路径>
|
||||
# 或: dsh plugin --profile web add link:<绝对路径>
|
||||
```
|
||||
|
||||
`link:` 会让源码更新直接作用于 profile。修改或升级浏览器 bundle 后需要重启 DSH Web 并刷新页面。
|
||||
`link:` 会让源码更新直接作用于 profile。Desktop 0.2 可从宿主解析 `@modelcontextprotocol/client` / `undici` / `ipaddr.js` peers;但仍建议在仓库内跑一次 `npm install`(并删掉空的 `node_modules\@modelcontextprotocol` 残留目录),避免解析踩空目录。修改或升级浏览器 bundle 后需要重启 DSH 并刷新页面。
|
||||
|
||||
如果 profile 中已有独立搜索 MCP 行,建议先移除重复入口,避免同时暴露 `mcp__...` 工具和本插件提供的 `web_search`。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
/** MCP transport layer for one search. */
|
||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
||||
/**
|
||||
* MCP transport layer for one search.
|
||||
*
|
||||
* Desktop 0.2 ships the split MCP client package (v2). Import that package so
|
||||
* link:/Desktop profiles can resolve it from the host graph without a local
|
||||
* `node_modules` copy of the legacy monolith SDK.
|
||||
*/
|
||||
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
|
||||
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
|
||||
import { WebError } from '@deepseek-ai/dsh-web';
|
||||
import { Agent, fetch as undiciFetch } from 'undici';
|
||||
import { clampSearchResults } from './catalog.js';
|
||||
|
|
@ -17,7 +22,10 @@ export async function callMcpSearch(server, key, args, signal) {
|
|||
}
|
||||
|
||||
let runtime;
|
||||
const client = new Client({ name: 'dsh-search-mcp', version: '0.2.0' }, { capabilities: {} });
|
||||
const client = new Client(
|
||||
{ name: 'dsh-search-mcp', version: '0.2.39' },
|
||||
{ capabilities: {}, versionNegotiation: { mode: 'auto' } },
|
||||
);
|
||||
try {
|
||||
runtime = server.transport === 'stdio'
|
||||
? { transport: stdioTransport(server, key), close: async () => {} }
|
||||
|
|
|
|||
1101
package-lock.json
generated
1101
package-lock.json
generated
File diff suppressed because it is too large
Load diff
20
package.json
20
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "dsh-search-mcp",
|
||||
"version": "0.2.38",
|
||||
"version": "0.2.39",
|
||||
"description": "Replace dsh's built-in web search with search MCP servers (Tavily / Brave / Exa / Perplexity / DuckDuckGo / custom), configured from the web Settings page. When this plugin is enabled the built-in DeepSeek search provider is disabled.",
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "1.30.0",
|
||||
"@modelcontextprotocol/client": "2.0.0",
|
||||
"ipaddr.js": "2.5.0",
|
||||
"undici": "6.28.0"
|
||||
},
|
||||
|
|
@ -58,6 +58,20 @@
|
|||
"@deepseek-ai/dsh-launch-environment": "*",
|
||||
"@deepseek-ai/dsh-settings": "*",
|
||||
"@deepseek-ai/dsh-web": "*",
|
||||
"@deepseek-ai/schemastery": "*"
|
||||
"@deepseek-ai/schemastery": "*",
|
||||
"@modelcontextprotocol/client": "*",
|
||||
"ipaddr.js": "*",
|
||||
"undici": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@modelcontextprotocol/client": {
|
||||
"optional": true
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"optional": true
|
||||
},
|
||||
"undici": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@ test('package exports resolve and peerDependencies stay open', async () => {
|
|||
assert.equal(pkg.exports['.'], './lib/index.js')
|
||||
assert.equal(pkg.exports['./client'], './lib/client.browser.js')
|
||||
assert.equal(pkg.engines.node, '>=20')
|
||||
assert.equal(pkg.version, '0.2.38')
|
||||
assert.equal(pkg.version, '0.2.39')
|
||||
assert.equal(pkg.dsh.client.immediately, false)
|
||||
assert.equal(pkg.dependencies['@modelcontextprotocol/client'], '2.0.0')
|
||||
assert.ok(!Object.hasOwn(pkg.dependencies, '@modelcontextprotocol/sdk'))
|
||||
|
||||
for (const name of [
|
||||
'@deepseek-ai/dsh-api-remotes',
|
||||
|
|
@ -22,6 +24,9 @@ test('package exports resolve and peerDependencies stay open', async () => {
|
|||
'@deepseek-ai/dsh-settings',
|
||||
'@deepseek-ai/dsh-web',
|
||||
'@deepseek-ai/schemastery',
|
||||
'@modelcontextprotocol/client',
|
||||
'ipaddr.js',
|
||||
'undici',
|
||||
]) {
|
||||
assert.equal(pkg.peerDependencies[name], '*')
|
||||
}
|
||||
|
|
@ -82,9 +87,13 @@ test('known providers are CDKey-only while custom keeps advanced fields', async
|
|||
|
||||
test('HTTP transport pins DNS and applies one guarded fetch to every SDK request', async () => {
|
||||
const transport = await read('lib/client.js')
|
||||
assert.match(transport, /from '@modelcontextprotocol\/client'/)
|
||||
assert.match(transport, /from '@modelcontextprotocol\/client\/stdio'/)
|
||||
assert.doesNotMatch(transport, /from ['"]@modelcontextprotocol\/sdk/)
|
||||
assert.match(transport, /validateHttpEndpoint\(server\.url, \{ signal \}\)/)
|
||||
assert.match(transport, /dispatcher: agent/)
|
||||
assert.match(transport, /redirect: 'error'/)
|
||||
assert.match(transport, /versionNegotiation:\s*\{\s*mode:\s*['"]auto['"]/)
|
||||
})
|
||||
|
||||
test('bundle inserts search-mcp without pinning web.searchProvider (Desktop 0.2 boot-safe)', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue