Merge pull request #154 from mouse-value-add/feat/youcom-search-integration
Add optional You.com search integration. Thanks @mouse-value-add for the contribution.
3 files · +69 -0
M examples/extensions/mcp-bridge/README.md +30 -0
| @@ -211,11 +211,41 @@ Standard MCP config — same as Claude Desktop, with zot-specific extensions: | |||
| 211 | 211 | "context7": { | |
| 212 | 212 | "command": "npx", | |
| 213 | 213 | "args": ["-y", "@upstash/context7-mcp@latest"] | |
| 214 | + | }, | |
| 215 | + | ||
| 216 | + | // You.com web search (streamable-http, keyless) | |
| 217 | + | "you": { | |
| 218 | + | "transport": "streamable-http", | |
| 219 | + | "url": "https://api.you.com/mcp?profile=free" | |
| 220 | + | } | |
| 221 | + | } | |
| 222 | + | } | |
| 223 | + | ``` | |
| 224 | + | ||
| 225 | + | ### You.com template | |
| 226 | + | ||
| 227 | + | `/mcp setup add you` registers the keyless You.com MCP profile | |
| 228 | + | (`you-search`). It needs no account or API key. To use the authenticated | |
| 229 | + | server and its additional tools, edit `$ZOT_HOME/mcp.json` after adding | |
| 230 | + | the template: | |
| 231 | + | ||
| 232 | + | ```jsonc | |
| 233 | + | { | |
| 234 | + | "mcpServers": { | |
| 235 | + | "you": { | |
| 236 | + | "transport": "streamable-http", | |
| 237 | + | "url": "https://api.you.com/mcp", | |
| 238 | + | "headers": { | |
| 239 | + | "Authorization": "Bearer YOUR_YDC_API_KEY" | |
| 240 | + | } | |
| 214 | 241 | } | |
| 215 | 242 | } | |
| 216 | 243 | } | |
| 217 | 244 | ``` | |
| 218 | 245 | ||
| 246 | + | The authenticated endpoint does not expose `you-finance` by default. Request | |
| 247 | + | it explicitly with the `?tools=` URL parameter or the `X-Allowed-Tools` header. | |
| 248 | + | ||
| 219 | 249 | ## How It Works | |
| 220 | 250 | ||
| 221 | 251 | ``` | |
| @@ -211,11 +211,41 @@ Standard MCP config — same as Claude Desktop, with zot-specific extensions: | |||||
| 211 | "context7": { | 211 | "context7": { | ||
| 212 | "command": "npx", | 212 | "command": "npx", | ||
| 213 | "args": ["-y", "@upstash/context7-mcp@latest"] | 213 | "args": ["-y", "@upstash/context7-mcp@latest"] | ||
| 214 | + | }, | |||
| 215 | + | ||||
| 216 | + | // You.com web search (streamable-http, keyless) | |||
| 217 | + | "you": { | |||
| 218 | + | "transport": "streamable-http", | |||
| 219 | + | "url": "https://api.you.com/mcp?profile=free" | |||
| 220 | + | } | |||
| 221 | + | } | |||
| 222 | + | } | |||
| 223 | + | ``` | |||
| 224 | + | ||||
| 225 | + | ### You.com template | |||
| 226 | + | ||||
| 227 | + | `/mcp setup add you` registers the keyless You.com MCP profile | |||
| 228 | + | (`you-search`). It needs no account or API key. To use the authenticated | |||
| 229 | + | server and its additional tools, edit `$ZOT_HOME/mcp.json` after adding | |||
| 230 | + | the template: | |||
| 231 | + | ||||
| 232 | + | ```jsonc | |||
| 233 | + | { | |||
| 234 | + | "mcpServers": { | |||
| 235 | + | "you": { | |||
| 236 | + | "transport": "streamable-http", | |||
| 237 | + | "url": "https://api.you.com/mcp", | |||
| 238 | + | "headers": { | |||
| 239 | + | "Authorization": "Bearer YOUR_YDC_API_KEY" | |||
| 240 | + | } | |||
| 214 | } | 241 | } | ||
| 215 | } | 242 | } | ||
| 216 | } | 243 | } | ||
| 217 | ``` | 244 | ``` | ||
| 218 | 245 | ||||
| 246 | + | The authenticated endpoint does not expose `you-finance` by default. Request | |||
| 247 | + | it explicitly with the `?tools=` URL parameter or the `X-Allowed-Tools` header. | |||
| 248 | + | ||||
| 219 | ## How It Works | 249 | ## How It Works | ||
| 220 | 250 | ||||
| 221 | ``` | 251 | ``` | ||
M examples/extensions/mcp-bridge/setup.go +10 -0
| @@ -62,6 +62,16 @@ func setupTemplates() map[string]serverTemplate { | |||
| 62 | 62 | } | |
| 63 | 63 | }, | |
| 64 | 64 | }, | |
| 65 | + | "you": { | |
| 66 | + | Name: "you", | |
| 67 | + | Description: "Current web search via the keyless You.com MCP server (you-search). Add an Authorization Bearer header with a YDC_API_KEY for additional authenticated tools.", | |
| 68 | + | Config: func(cwd string) ServerConfig { | |
| 69 | + | return ServerConfig{ | |
| 70 | + | Transport: "streamable-http", | |
| 71 | + | URL: "https://api.you.com/mcp?profile=free", | |
| 72 | + | } | |
| 73 | + | }, | |
| 74 | + | }, | |
| 65 | 75 | } | |
| 66 | 76 | } | |
| 67 | 77 | ||
| @@ -62,6 +62,16 @@ func setupTemplates() map[string]serverTemplate { | |||||
| 62 | } | 62 | } | ||
| 63 | }, | 63 | }, | ||
| 64 | }, | 64 | }, | ||
| 65 | + | "you": { | |||
| 66 | + | Name: "you", | |||
| 67 | + | Description: "Current web search via the keyless You.com MCP server (you-search). Add an Authorization Bearer header with a YDC_API_KEY for additional authenticated tools.", | |||
| 68 | + | Config: func(cwd string) ServerConfig { | |||
| 69 | + | return ServerConfig{ | |||
| 70 | + | Transport: "streamable-http", | |||
| 71 | + | URL: "https://api.you.com/mcp?profile=free", | |||
| 72 | + | } | |||
| 73 | + | }, | |||
| 74 | + | }, | |||
| 65 | } | 75 | } | ||
| 66 | } | 76 | } | ||
| 67 | 77 | ||||
M examples/extensions/mcp-bridge/setup_test.go +29 -0
| @@ -58,6 +58,35 @@ func TestHandleSetupAddFilesystemProject(t *testing.T) { | |||
| 58 | 58 | } | |
| 59 | 59 | } | |
| 60 | 60 | ||
| 61 | + | func TestHandleSetupAddYouGlobal(t *testing.T) { | |
| 62 | + | tmp := t.TempDir() | |
| 63 | + | t.Setenv("ZOT_HOME", tmp) | |
| 64 | + | ||
| 65 | + | out, err := handleSetup([]string{"add", "you"}, tmp) | |
| 66 | + | if err != nil { | |
| 67 | + | t.Fatalf("handleSetup add you: %v", err) | |
| 68 | + | } | |
| 69 | + | if out == "" { | |
| 70 | + | t.Fatal("expected setup output") | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | data, err := os.ReadFile(filepath.Join(tmp, "mcp.json")) | |
| 74 | + | if err != nil { | |
| 75 | + | t.Fatalf("read mcp.json: %v", err) | |
| 76 | + | } | |
| 77 | + | var cfg Config | |
| 78 | + | if err := json.Unmarshal(data, &cfg); err != nil { | |
| 79 | + | t.Fatalf("parse mcp.json: %v", err) | |
| 80 | + | } | |
| 81 | + | you := cfg.MCPServers["you"] | |
| 82 | + | if you.Transport != "streamable-http" || you.URL != "https://api.you.com/mcp?profile=free" { | |
| 83 | + | t.Fatalf("unexpected you config: %+v", you) | |
| 84 | + | } | |
| 85 | + | if len(you.Headers) != 0 { | |
| 86 | + | t.Fatalf("keyless template must not write auth headers: %+v", you.Headers) | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 61 | 90 | func TestHandleSetupDuplicate(t *testing.T) { | |
| 62 | 91 | tmp := t.TempDir() | |
| 63 | 92 | t.Setenv("ZOT_HOME", tmp) | |
| @@ -58,6 +58,35 @@ func TestHandleSetupAddFilesystemProject(t *testing.T) { | |||||
| 58 | } | 58 | } | ||
| 59 | } | 59 | } | ||
| 60 | 60 | ||||
| 61 | + | func TestHandleSetupAddYouGlobal(t *testing.T) { | |||
| 62 | + | tmp := t.TempDir() | |||
| 63 | + | t.Setenv("ZOT_HOME", tmp) | |||
| 64 | + | ||||
| 65 | + | out, err := handleSetup([]string{"add", "you"}, tmp) | |||
| 66 | + | if err != nil { | |||
| 67 | + | t.Fatalf("handleSetup add you: %v", err) | |||
| 68 | + | } | |||
| 69 | + | if out == "" { | |||
| 70 | + | t.Fatal("expected setup output") | |||
| 71 | + | } | |||
| 72 | + | ||||
| 73 | + | data, err := os.ReadFile(filepath.Join(tmp, "mcp.json")) | |||
| 74 | + | if err != nil { | |||
| 75 | + | t.Fatalf("read mcp.json: %v", err) | |||
| 76 | + | } | |||
| 77 | + | var cfg Config | |||
| 78 | + | if err := json.Unmarshal(data, &cfg); err != nil { | |||
| 79 | + | t.Fatalf("parse mcp.json: %v", err) | |||
| 80 | + | } | |||
| 81 | + | you := cfg.MCPServers["you"] | |||
| 82 | + | if you.Transport != "streamable-http" || you.URL != "https://api.you.com/mcp?profile=free" { | |||
| 83 | + | t.Fatalf("unexpected you config: %+v", you) | |||
| 84 | + | } | |||
| 85 | + | if len(you.Headers) != 0 { | |||
| 86 | + | t.Fatalf("keyless template must not write auth headers: %+v", you.Headers) | |||
| 87 | + | } | |||
| 88 | + | } | |||
| 89 | + | ||||
| 61 | func TestHandleSetupDuplicate(t *testing.T) { | 90 | func TestHandleSetupDuplicate(t *testing.T) { | ||
| 62 | tmp := t.TempDir() | 91 | tmp := t.TempDir() | ||
| 63 | t.Setenv("ZOT_HOME", tmp) | 92 | t.Setenv("ZOT_HOME", tmp) | ||