test: refresh live deepwiki smoke

This commit is contained in:
Peter Steinberger 2026-03-29 09:40:39 +09:00
parent 83cc3b9a4c
commit b69dd07dba
No known key found for this signature in database
3 changed files with 58 additions and 46 deletions

View File

@ -3,19 +3,19 @@
## [Unreleased]
### CLI
- `mcporter config add` now accepts plural `--args` as an alias for repeated stdio arguments, matching common CLI muscle memory. (PR #93, thanks @Jah-yee)
- Preserve OAuth flow vs post-auth transport failures so invalid OAuth/provider errors surface directly, while real legacy 404/405 transport mismatches still fall back to SSE correctly. (PR #97, thanks @mavam)
- Ignore static `Authorization` headers once OAuth is active so imported editor configs cannot override fresh OAuth tokens. (PR #123, thanks @ahonn)
- Keep `mcporter call --output json` parseable by emitting valid JSON even when the command falls back to raw output. (PR #128, thanks @armanddp)
- Render `resource` content blocks in call output helpers instead of dropping them, including markdown resources and JSON text payloads. (PR #124, thanks @mvanhorn)
- Preserve full JSON/error payloads when `data` is just one field instead of collapsing the response to `data` alone. (PR #106, thanks @AielloChan)
- Generated CLIs now parse object-valued flags as JSON and render object placeholders/examples with JSON-shaped help text, so tools like Jira `fields` no longer receive raw strings. (PR #114, thanks @v2nic)
- Deduplicate concurrent keep-alive daemon restarts per server so repeated fatal errors only force-close the cached daemon transport once before retrying. (PR #125, thanks @zm2231)
- Keep `mcporter call --output json` parseable by emitting valid JSON even when the command falls back to raw output. (PR #128, thanks @armanddp)
- Ignore static `Authorization` headers once OAuth is active so imported editor configs cannot override fresh OAuth tokens. (PR #123, thanks @ahonn)
- Preserve full JSON/error payloads when `data` is just one field instead of collapsing the response to `data` alone. (PR #106, thanks @AielloChan)
- Render `resource` content blocks in call output helpers instead of dropping them, including markdown resources and JSON text payloads. (PR #124, thanks @mvanhorn)
- Preserve OAuth flow vs post-auth transport failures so invalid OAuth/provider errors surface directly, while real legacy 404/405 transport mismatches still fall back to SSE correctly. (PR #97, thanks @mavam)
- `mcporter config add` now accepts plural `--args` as an alias for repeated stdio arguments, matching common CLI muscle memory. (PR #93, thanks @Jah-yee)
- Preserve default imports when `mcporter config add` writes a config file, instead of forcing `"imports": []`.
- OAuth: avoid crashing on headless Linux when `xdg-open` is unavailable; clear stale dynamic-port client registrations; close callback server if stale-client persistence reads fail. (PR #72, thanks @mgonto)
- Added optional `oauthScope`/`oauth_scope` config override as an escape hatch for providers that require explicit scopes.
- `createCallResult().json()` now collects all parseable JSON entries from MCP content arrays (single item stays backward-compatible), and raw inspect depth now stays readable without unbounded traversal. (PR #91, thanks @Blankdlh)
- OAuth wait/redirect now share one deferred to eliminate authorization race windows and preserve stable close-path errors, including wait-before-redirect and repeated-redirect flows. (PR #70, thanks @monotykamary)
- `createCallResult().json()` now collects all parseable JSON entries from MCP content arrays (single item stays backward-compatible), and raw inspect depth now stays readable without unbounded traversal. (PR #91, thanks @Blankdlh)
- Added `--raw-strings` (numeric coercion off) and `--no-coerce` (all coercion off) for `mcporter call` argument parsing so IDs/codes can stay literal strings. (PR #59, thanks @nobrainer-tech)
- Added `CallResult.images()` plus opt-in `mcporter call --save-images <dir>` so image content blocks can be persisted without changing existing stdout output contracts. (PR #61, thanks @daniella-11ways)
- OAuth transport retries now classify HTTP 405 as HTTP (not auth) and OAuth promotion applies to configured HTTP servers too, so post-auth fallback flows no longer drop credentials on 405-only endpoints. (PR #48, thanks @caseyg)

View File

@ -20,12 +20,15 @@ MCP_LIVE_TESTS=1 pnpm test:live
This runs the Vitest suite under `tests/live`, in-band, with longer timeouts.
## Current coverage
- **DeepWiki** (both wire protocols):
- Streamable HTTP: `https://mcp.deepwiki.com/mcp`
- SSE: `https://mcp.deepwiki.com/sse`
- Test: calls `read_wiki_structure repoName:facebook/react` and asserts a non-empty result.
- **DeepWiki**:
- Streamable HTTP success path: `https://mcp.deepwiki.com/mcp`
- Deprecated SSE endpoint classification: `https://mcp.deepwiki.com/sse`
- Tests:
- call `read_wiki_structure repoName:facebook/react` and assert a non-empty result over Streamable HTTP
- assert the legacy SSE endpoint currently returns a structured HTTP `410` issue envelope
## Notes
- Tests are skipped entirely unless `MCP_LIVE_TESTS=1` is set.
- Ensure network egress is allowed. No secrets are required for the current DeepWiki checks.
- As of 2026-03-29, DeepWiki's hosted `/sse` endpoint responds with HTTP `410`, so the live suite treats that as a compatibility/error-classification smoke rather than a success-path transport check.
- Keep assertions minimal to reduce flake; these are availability smokes, not full contract tests.

View File

@ -3,10 +3,8 @@ import { promisify } from 'node:util';
import { describe, expect, it } from 'vitest';
const LIVE_FLAG = process.env.MCP_LIVE_TESTS === '1';
const ENDPOINTS = [
{ name: 'streamable-http', url: 'https://mcp.deepwiki.com/mcp' },
{ name: 'sse', url: 'https://mcp.deepwiki.com/sse' },
];
const STREAMABLE_HTTP_URL = 'https://mcp.deepwiki.com/mcp';
const SSE_URL = 'https://mcp.deepwiki.com/sse';
const execFileAsync = promisify(execFile);
@ -18,36 +16,47 @@ function skipReason(): string | undefined {
}
describe.skipIf(Boolean(skipReason()))('deepwiki live', () => {
ENDPOINTS.forEach(({ name, url }) => {
it(`lists wiki structure via ${name}`, async () => {
const { stdout, stderr } = await execFileAsync('node', [
'dist/cli.js',
'call',
url,
'read_wiki_structure',
'repoName:facebook/react',
'--output',
'json',
]);
const normalized = stdout.trim() || stderr.trim();
// Response comes back as a JS-object literal string; just assert it contains the section list.
expect(normalized).toContain('Available pages for facebook/react');
expect(normalized).toContain('Overview');
}, 30_000);
it('lists wiki structure via streamable-http', async () => {
const { stdout, stderr } = await execFileAsync('node', [
'dist/cli.js',
'call',
STREAMABLE_HTTP_URL,
'read_wiki_structure',
'repoName:facebook/react',
'--output',
'json',
]);
const normalized = stdout.trim() || stderr.trim();
expect(normalized).toContain('Available pages for facebook/react');
expect(normalized).toContain('Overview');
}, 30_000);
it(`prints plain text when default output is used via ${name}`, async () => {
const { stdout, stderr } = await execFileAsync('node', [
'dist/cli.js',
'call',
url,
'read_wiki_structure',
'repoName:facebook/react',
]);
const normalized = (stdout || stderr).trim();
expect(normalized).toContain('Available pages for facebook/react');
// Ensure we rendered the text content, not the JSON envelope.
expect(normalized).not.toContain('"type"');
expect(normalized.startsWith('{')).toBe(false);
}, 30_000);
});
it('prints the readable result when default output is used via streamable-http', async () => {
const { stdout, stderr } = await execFileAsync('node', [
'dist/cli.js',
'call',
STREAMABLE_HTTP_URL,
'read_wiki_structure',
'repoName:facebook/react',
]);
const normalized = (stdout || stderr).trim();
expect(normalized).toContain('Available pages for facebook/react');
expect(normalized).toContain('Overview');
expect(normalized).not.toContain('"type"');
}, 30_000);
it('reports the deprecated sse endpoint as a structured 410 issue', async () => {
const { stdout, stderr } = await execFileAsync('node', [
'dist/cli.js',
'call',
SSE_URL,
'read_wiki_structure',
'repoName:facebook/react',
'--output',
'json',
]);
const normalized = stdout.trim() || stderr.trim();
expect(normalized).toContain('"statusCode": 410');
expect(normalized).toContain('"kind": "http"');
}, 30_000);
});