@gemus/mcp-proxy 0.1.9 → 0.1.10
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/README.md +41 -21
- package/package.json +3 -2
- package/src/proxy.mjs +29 -427
- package/src/relay.mjs +440 -0
- package/src/setup/cli.mjs +130 -0
- package/src/setup/codex.mjs +110 -0
- package/src/setup/config.mjs +530 -0
- package/src/setup/configFile.mjs +155 -0
- package/src/setup/environment.mjs +79 -0
- package/src/setup/secret.mjs +91 -0
- package/src/__tests__/backfill.test.ts +0 -394
- package/src/__tests__/failFast.test.ts +0 -356
- package/src/__tests__/fixtures/proxy-runtime-loader.mjs +0 -216
- package/src/__tests__/mcpHeaders.test.ts +0 -32
- package/src/__tests__/proxyMessages.test.ts +0 -81
- package/src/__tests__/route.integration.test.ts +0 -68
- package/src/__tests__/startup.test.ts +0 -752
- package/src/__tests__/upstreamHttp.real.test.ts +0 -37
- package/src/__tests__/upstreamHttp.test.ts +0 -151
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
3
|
-
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Opt-in integration test against a REAL running gemus `/api/mcp` route (#1751). Validates the Mode-B
|
|
7
|
-
* **key-only** contract the proxy + core delivery rely on: Bearer `mak_` auth with **no**
|
|
8
|
-
* `X-Gemus-Session-Id` header, and addressing by an explicit real `workflowId`.
|
|
9
|
-
*
|
|
10
|
-
* Excluded from the default runner (`*.integration.test.ts`) and gated on env so it never runs in CI or
|
|
11
|
-
* by accident. To run against local dev:
|
|
12
|
-
* GEMUS_IT_KEY=mak_... GEMUS_IT_WORKFLOW=<realWorkflowId> \
|
|
13
|
-
* pnpm exec vitest run packages/gemus-mcp-proxy/src/__tests__/route.integration.test.ts
|
|
14
|
-
* (GEMUS_IT_URL defaults to http://localhost:3000/api/mcp.) All calls here are read-only (no mutation).
|
|
15
|
-
*
|
|
16
|
-
* connect-per-call invariant: every case opens + closes its own client (fresh connectionNonce, #1744).
|
|
17
|
-
*/
|
|
18
|
-
const KEY = process.env.GEMUS_IT_KEY
|
|
19
|
-
const URL_ = process.env.GEMUS_IT_URL || 'http://localhost:3000/api/mcp'
|
|
20
|
-
const WORKFLOW = process.env.GEMUS_IT_WORKFLOW
|
|
21
|
-
|
|
22
|
-
/** Key-only client: Bearer only, deliberately NO X-Gemus-Session-Id (the Mode-B contract). */
|
|
23
|
-
async function connectKeyOnly() {
|
|
24
|
-
const client = new Client({ name: 'gemus-proxy-it', version: '0.1.0' })
|
|
25
|
-
const transport = new StreamableHTTPClientTransport(new URL(URL_), {
|
|
26
|
-
requestInit: { headers: { Authorization: `Bearer ${KEY}` } },
|
|
27
|
-
})
|
|
28
|
-
await client.connect(transport)
|
|
29
|
-
return client
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
describe.skipIf(!KEY)('key-only /api/mcp route (real, opt-in)', () => {
|
|
33
|
-
it('relays the full tool surface incl. execute/batch_execute (no session header)', async () => {
|
|
34
|
-
const client = await connectKeyOnly()
|
|
35
|
-
try {
|
|
36
|
-
const { tools } = await client.listTools()
|
|
37
|
-
const names = tools.map((t) => t.name)
|
|
38
|
-
expect(names).toEqual(expect.arrayContaining(['execute', 'batch_execute', 'canvas_read', 'canvas_edit']))
|
|
39
|
-
} finally {
|
|
40
|
-
await client.close()
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('serves resources (skills / knowledge) through the key-only connection', async () => {
|
|
45
|
-
const client = await connectKeyOnly()
|
|
46
|
-
try {
|
|
47
|
-
const { resources } = await client.listResources()
|
|
48
|
-
// The route exposes skill:// / knowledge:// resources; a tool-only passthrough would drop these.
|
|
49
|
-
expect(Array.isArray(resources)).toBe(true)
|
|
50
|
-
} finally {
|
|
51
|
-
await client.close()
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it.skipIf(!WORKFLOW)('addresses a real workflow by explicit workflowId (key-only, no activeContext)', async () => {
|
|
56
|
-
const client = await connectKeyOnly()
|
|
57
|
-
try {
|
|
58
|
-
// canvas_read is read-only; success proves key-only addressing by explicit workflowId works
|
|
59
|
-
// without a session header (what deliverImageToNode relies on in Mode B).
|
|
60
|
-
const res = (await client.callTool({ name: 'canvas_read', arguments: { workflowId: WORKFLOW } })) as {
|
|
61
|
-
isError?: boolean
|
|
62
|
-
}
|
|
63
|
-
expect(res.isError).not.toBe(true)
|
|
64
|
-
} finally {
|
|
65
|
-
await client.close()
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
})
|