@hyperstar/mcp 0.1.15 → 0.1.17
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/LICENSE +8 -0
- package/README.md +116 -31
- package/dist/config.d.ts +8 -1
- package/dist/config.js +25 -2
- package/dist/http.js +4 -1
- package/dist/index.js +4 -3
- package/dist/server.js +7 -3
- package/dist/workspaces.d.ts +2 -1
- package/dist/workspaces.js +15 -1
- package/package.json +3 -2
- package/scripts/npm-clean-room-smoke.mjs +126 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Hyperstar MCP Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Hyperstar. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This package is published for use with Hyperstar services. The package and its
|
|
6
|
+
contents are proprietary. No permission is granted to copy, modify, distribute,
|
|
7
|
+
sublicense, or use this package except as expressly authorized by Hyperstar.
|
|
8
|
+
|
package/README.md
CHANGED
|
@@ -5,10 +5,19 @@ workflows. It exposes scoped creator search, campaign roster, bulk email, and
|
|
|
5
5
|
inbox tools for MCP clients using either a service-account key or local browser
|
|
6
6
|
CLI login.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
This README is self-contained for first-time agent setup. You do not need
|
|
9
|
+
access to the Hyperstar source repository to install the package, configure an
|
|
10
|
+
MCP client, or understand the safe workflow order.
|
|
10
11
|
|
|
11
|
-
##
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- Node.js `22.12.0` or newer.
|
|
15
|
+
- An active Hyperstar account with access to at least one workspace.
|
|
16
|
+
- Either a service-account API key or permission to approve local browser CLI
|
|
17
|
+
login.
|
|
18
|
+
- An MCP-capable client that can launch a local stdio server.
|
|
19
|
+
|
|
20
|
+
## Install And Login
|
|
12
21
|
|
|
13
22
|
Run the MCP server directly from npm:
|
|
14
23
|
|
|
@@ -32,29 +41,18 @@ path, use the equivalent `npm exec` form:
|
|
|
32
41
|
npm exec --yes --package @hyperstar/mcp -- hyperstar-mcp
|
|
33
42
|
```
|
|
34
43
|
|
|
35
|
-
For
|
|
44
|
+
For interactive local use, start with browser login. The CLI opens Hyperstar in
|
|
45
|
+
your browser and never asks for a raw Hyperstar password in the terminal:
|
|
36
46
|
|
|
37
47
|
```sh
|
|
38
48
|
npx -y --package @hyperstar/mcp hyperstar login
|
|
39
49
|
npx -y --package @hyperstar/mcp hyperstar workspaces list --json
|
|
40
|
-
npx -y --package @hyperstar/mcp hyperstar workspaces use
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
For unreleased local package testing, pack from the package directory and use
|
|
44
|
-
the filename printed by `npm pack`:
|
|
45
|
-
|
|
46
|
-
```sh
|
|
47
|
-
cd projects/hyperstar-mcp
|
|
48
|
-
TARBALL=$(npm pack --silent)
|
|
49
|
-
npx -y --package "./$TARBALL" hyperstar-mcp
|
|
50
|
-
npx -y --package "./$TARBALL" hyperstar login
|
|
51
|
-
npx -y --package "./$TARBALL" hyperstar workspaces list --json
|
|
52
|
-
npx -y --package "./$TARBALL" hyperstar workspaces use org_123
|
|
50
|
+
npx -y --package @hyperstar/mcp hyperstar workspaces use <organization_id>
|
|
53
51
|
```
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
For unattended automation, create a service-account key from Team -> API keys in
|
|
54
|
+
the dashboard. Use the headless workflow preset. Enable inbox write only for
|
|
55
|
+
agents that are allowed to send inbox replies.
|
|
58
56
|
|
|
59
57
|
## MCP client config
|
|
60
58
|
|
|
@@ -106,8 +104,11 @@ when `HYPERSTAR_API_KEY` is used. For non-production login, set matching
|
|
|
106
104
|
## Tools
|
|
107
105
|
|
|
108
106
|
Agents should start by reading `get_hyperstar_workflow_guide` or the MCP
|
|
109
|
-
resources/prompts listed below.
|
|
110
|
-
|
|
107
|
+
resources/prompts listed below. The MCP server starts without auth so clients
|
|
108
|
+
can discover tools and guides first; Product API workflow calls still require
|
|
109
|
+
local browser login or `HYPERSTAR_API_KEY`. Tool responses include
|
|
110
|
+
`agent_guidance` and, where the next step is deterministic, `next_tool` and
|
|
111
|
+
`next_arguments`.
|
|
111
112
|
|
|
112
113
|
- `hyperstar_whoami`
|
|
113
114
|
- `list_workspaces`
|
|
@@ -144,18 +145,59 @@ It also exposes matching prompts:
|
|
|
144
145
|
- `hyperstar_bulk_email_safety`
|
|
145
146
|
- `hyperstar_inbox_workflow`
|
|
146
147
|
|
|
147
|
-
##
|
|
148
|
+
## First Agent Prompts
|
|
148
149
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
Use prompts like these with a newly connected agent:
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
Use the Hyperstar MCP tools. First, discover the available Hyperstar workflow
|
|
154
|
+
guides and tell me the safe order for search, campaign save, bulk email, and
|
|
155
|
+
inbox handling.
|
|
154
156
|
```
|
|
155
157
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
```text
|
|
159
|
+
Use Hyperstar to search TikTok creators in the US for ceramic mug reviewers.
|
|
160
|
+
Return only a compact summary and explain the next tool I should approve before
|
|
161
|
+
saving anything to a campaign.
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
List my Hyperstar campaigns and explain how you would safely check bulk email
|
|
166
|
+
readiness for one campaign without starting a real send.
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
List recent Hyperstar inbox threads, then read the full messages for one thread
|
|
171
|
+
before drafting any reply. Do not send a reply unless I explicitly authorize it.
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Workflow Safety
|
|
175
|
+
|
|
176
|
+
Agents should start with `get_hyperstar_workflow_guide` or the MCP guide
|
|
177
|
+
resources. The server exposes these main workflow tools:
|
|
178
|
+
|
|
179
|
+
- `search_creators`
|
|
180
|
+
- `get_search_results`
|
|
181
|
+
- `list_campaigns`
|
|
182
|
+
- `create_campaign`
|
|
183
|
+
- `save_search_results_to_campaign`
|
|
184
|
+
- `list_campaign_creators`
|
|
185
|
+
- `check_bulk_email_readiness`
|
|
186
|
+
- `start_bulk_email`
|
|
187
|
+
- `get_bulk_email_job`
|
|
188
|
+
- `list_inbox_threads`
|
|
189
|
+
- `get_inbox_thread_messages`
|
|
190
|
+
- `update_inbox_thread_state`
|
|
191
|
+
- `send_inbox_reply`
|
|
192
|
+
|
|
193
|
+
`start_bulk_email` and `send_inbox_reply` perform real sends. Both require
|
|
194
|
+
`send_confirmation: "user_authorized"` and a stable `idempotency_key`. Agents
|
|
195
|
+
should call readiness and full-thread read tools before asking for send
|
|
196
|
+
authorization.
|
|
197
|
+
|
|
198
|
+
Search result tools return compact creator summaries by default. Bulk campaign
|
|
199
|
+
import uses `search_id` server-side, so the agent does not need to paste an
|
|
200
|
+
entire creator list into its context window.
|
|
159
201
|
|
|
160
202
|
## Examples
|
|
161
203
|
|
|
@@ -301,3 +343,46 @@ history:
|
|
|
301
343
|
}
|
|
302
344
|
}
|
|
303
345
|
```
|
|
346
|
+
|
|
347
|
+
## Clean-Room Smoke Check
|
|
348
|
+
|
|
349
|
+
Without a repository checkout, verify npm can resolve the package and both
|
|
350
|
+
binaries can start:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
npm view @hyperstar/mcp version --silent
|
|
354
|
+
npm exec --yes --package @hyperstar/mcp -- hyperstar --help
|
|
355
|
+
npm exec --yes --package @hyperstar/mcp -- hyperstar-mcp --help
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
These checks do not authenticate and do not call Hyperstar workflow APIs. They
|
|
359
|
+
prove that npm can resolve the package and both binaries can start. The package
|
|
360
|
+
smoke script also verifies unauthenticated MCP `tools/list`, `resources/list`,
|
|
361
|
+
and `prompts/list` discovery.
|
|
362
|
+
|
|
363
|
+
## Troubleshooting
|
|
364
|
+
|
|
365
|
+
- `npm error could not determine executable to run`: use the explicit
|
|
366
|
+
`--package @hyperstar/mcp -- hyperstar` or
|
|
367
|
+
`--package @hyperstar/mcp -- hyperstar-mcp` form because the package exposes
|
|
368
|
+
multiple binaries.
|
|
369
|
+
- `No Hyperstar auth configured`: run `hyperstar login` and select a workspace,
|
|
370
|
+
or set `HYPERSTAR_API_KEY` in the MCP server environment.
|
|
371
|
+
- Workspace errors in browser-login mode: run
|
|
372
|
+
`hyperstar workspaces list --json`, then
|
|
373
|
+
`hyperstar workspaces use <organization_id>`.
|
|
374
|
+
- Non-production login opens the wrong app: set both `HYPERSTAR_API_BASE_URL`
|
|
375
|
+
and `HYPERSTAR_APP_BASE_URL`.
|
|
376
|
+
|
|
377
|
+
## Development
|
|
378
|
+
|
|
379
|
+
```sh
|
|
380
|
+
npm install
|
|
381
|
+
npm test
|
|
382
|
+
npm run build
|
|
383
|
+
npm run smoke:npm
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
`npm run smoke:npm` verifies the published npm package can be resolved and that
|
|
387
|
+
both package binaries print help without requiring local build artifacts,
|
|
388
|
+
authentication, or real workflow API calls.
|
package/dist/config.d.ts
CHANGED
|
@@ -12,7 +12,11 @@ export type CliConfig = {
|
|
|
12
12
|
readonly accessTokenProvider: CliAccessTokenProvider;
|
|
13
13
|
readonly workspaceSelection: CliWorkspaceSelection;
|
|
14
14
|
};
|
|
15
|
-
export type
|
|
15
|
+
export type UnauthenticatedConfig = {
|
|
16
|
+
readonly authMode: "unauthenticated";
|
|
17
|
+
readonly apiBaseUrl: string;
|
|
18
|
+
};
|
|
19
|
+
export type HyperstarMcpConfig = ServiceAccountConfig | CliConfig | UnauthenticatedConfig;
|
|
16
20
|
export type Env = Readonly<Record<string, string | undefined>>;
|
|
17
21
|
export type CliWorkspaceSelection = {
|
|
18
22
|
readonly getSelectedOrganizationId: () => Promise<string | undefined>;
|
|
@@ -20,6 +24,7 @@ export type CliWorkspaceSelection = {
|
|
|
20
24
|
};
|
|
21
25
|
export declare const DEFAULT_API_BASE_URL = "https://autopilot.hyper-star.org";
|
|
22
26
|
export declare const DEFAULT_APP_BASE_URL = "https://app.hyper-star.org";
|
|
27
|
+
export declare const AUTH_CONFIGURATION_MESSAGE = "Run `hyperstar login` or set HYPERSTAR_API_KEY";
|
|
23
28
|
export type LoadConfigOptions = {
|
|
24
29
|
readonly env?: Env;
|
|
25
30
|
readonly fetcher?: Fetcher | undefined;
|
|
@@ -27,6 +32,8 @@ export type LoadConfigOptions = {
|
|
|
27
32
|
};
|
|
28
33
|
/** Load MCP configuration from env or persisted CLI auth state. */
|
|
29
34
|
export declare function loadConfig(options?: Env | LoadConfigOptions): HyperstarMcpConfig;
|
|
35
|
+
/** Load config for MCP server startup, allowing unauthenticated discovery. */
|
|
36
|
+
export declare function loadServerConfig(options?: Env | LoadConfigOptions): HyperstarMcpConfig;
|
|
30
37
|
/** Create the local CLI workspace-selection port backed by auth state. */
|
|
31
38
|
export declare function createCliWorkspaceSelection(store: CliAuthStateStore): CliWorkspaceSelection;
|
|
32
39
|
/** Redact an API key or bearer token for error messages. */
|
package/dist/config.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createCliAuthClient, createStoredCliAccessTokenProvider, } from "./auth
|
|
|
2
2
|
import { createFileCliAuthStateStore, } from "./auth/cli-auth-state.js";
|
|
3
3
|
export const DEFAULT_API_BASE_URL = "https://autopilot.hyper-star.org";
|
|
4
4
|
export const DEFAULT_APP_BASE_URL = "https://app.hyper-star.org";
|
|
5
|
+
export const AUTH_CONFIGURATION_MESSAGE = "Run `hyperstar login` or set HYPERSTAR_API_KEY";
|
|
5
6
|
/** Load MCP configuration from env or persisted CLI auth state. */
|
|
6
7
|
export function loadConfig(options = process.env) {
|
|
7
8
|
const loadOptions = isLoadConfigOptions(options) ? options : { env: options };
|
|
@@ -24,7 +25,7 @@ export function loadConfig(options = process.env) {
|
|
|
24
25
|
const store = createFileCliAuthStateStore({ env });
|
|
25
26
|
const state = store.readSync();
|
|
26
27
|
if (state === null) {
|
|
27
|
-
throw new Error(
|
|
28
|
+
throw new Error(AUTH_CONFIGURATION_MESSAGE);
|
|
28
29
|
}
|
|
29
30
|
const stateApiBaseUrl = normalizeBaseUrl(state.apiBaseUrl, "stored Hyperstar auth API base URL");
|
|
30
31
|
const rawCliApiBaseUrl = env.HYPERSTAR_API_BASE_URL?.trim();
|
|
@@ -52,6 +53,28 @@ export function loadConfig(options = process.env) {
|
|
|
52
53
|
workspaceSelection: createCliWorkspaceSelection(store),
|
|
53
54
|
};
|
|
54
55
|
}
|
|
56
|
+
/** Load config for MCP server startup, allowing unauthenticated discovery. */
|
|
57
|
+
export function loadServerConfig(options = process.env) {
|
|
58
|
+
try {
|
|
59
|
+
return loadConfig(options);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (!(error instanceof Error) ||
|
|
63
|
+
error.message !== AUTH_CONFIGURATION_MESSAGE) {
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
const loadOptions = isLoadConfigOptions(options)
|
|
67
|
+
? options
|
|
68
|
+
: { env: options };
|
|
69
|
+
const env = loadOptions.env ?? process.env;
|
|
70
|
+
const rawBaseUrl = env.HYPERSTAR_API_BASE_URL?.trim() ?? DEFAULT_API_BASE_URL;
|
|
71
|
+
const apiBaseUrl = normalizeBaseUrl(rawBaseUrl.length === 0 ? DEFAULT_API_BASE_URL : rawBaseUrl, "HYPERSTAR_API_BASE_URL");
|
|
72
|
+
return {
|
|
73
|
+
authMode: "unauthenticated",
|
|
74
|
+
apiBaseUrl,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
55
78
|
/** Create the local CLI workspace-selection port backed by auth state. */
|
|
56
79
|
export function createCliWorkspaceSelection(store) {
|
|
57
80
|
return {
|
|
@@ -60,7 +83,7 @@ export function createCliWorkspaceSelection(store) {
|
|
|
60
83
|
await store.withExclusiveLock(async () => {
|
|
61
84
|
const state = await store.read();
|
|
62
85
|
if (state === null) {
|
|
63
|
-
throw new Error(
|
|
86
|
+
throw new Error(AUTH_CONFIGURATION_MESSAGE);
|
|
64
87
|
}
|
|
65
88
|
await store.write({
|
|
66
89
|
...state,
|
package/dist/http.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { redactSecret } from "./config.js";
|
|
1
|
+
import { AUTH_CONFIGURATION_MESSAGE, redactSecret, } from "./config.js";
|
|
2
2
|
export class HyperstarApiError extends Error {
|
|
3
3
|
status;
|
|
4
4
|
detail;
|
|
@@ -24,6 +24,9 @@ export function createHyperstarClient(options) {
|
|
|
24
24
|
};
|
|
25
25
|
const secretsToRedact = [];
|
|
26
26
|
let retryCliAccessToken;
|
|
27
|
+
if (options.config.authMode === "unauthenticated") {
|
|
28
|
+
throw new Error(AUTH_CONFIGURATION_MESSAGE);
|
|
29
|
+
}
|
|
27
30
|
if (options.config.authMode === "service_account") {
|
|
28
31
|
baseHeaders["x-hyperstar-api-key"] = options.config.apiKey;
|
|
29
32
|
secretsToRedact.push(options.config.apiKey);
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import {
|
|
3
|
+
import { loadServerConfig } from "./config.js";
|
|
4
4
|
import { createHyperstarMcpServer } from "./server.js";
|
|
5
5
|
const MCP_SERVER_USAGE = [
|
|
6
6
|
"Usage: hyperstar-mcp [--help]",
|
|
@@ -8,7 +8,8 @@ const MCP_SERVER_USAGE = [
|
|
|
8
8
|
"Starts the Hyperstar stdio MCP server.",
|
|
9
9
|
"",
|
|
10
10
|
"Authentication:",
|
|
11
|
-
"
|
|
11
|
+
" Tools and guides are discoverable before auth.",
|
|
12
|
+
" Product API calls require `hyperstar login` or HYPERSTAR_API_KEY.",
|
|
12
13
|
].join("\n");
|
|
13
14
|
/** Start the stdio MCP server process. */
|
|
14
15
|
async function main() {
|
|
@@ -16,7 +17,7 @@ async function main() {
|
|
|
16
17
|
process.stdout.write(`${MCP_SERVER_USAGE}\n`);
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
|
-
const config =
|
|
20
|
+
const config = loadServerConfig();
|
|
20
21
|
const server = createHyperstarMcpServer(config);
|
|
21
22
|
await server.connect(new StdioServerTransport());
|
|
22
23
|
}
|
package/dist/server.js
CHANGED
|
@@ -10,8 +10,12 @@ export function createHyperstarMcpServer(config) {
|
|
|
10
10
|
version: packageVersion(),
|
|
11
11
|
});
|
|
12
12
|
registerHyperstarDiscovery(server, { apiBaseUrl: config.apiBaseUrl });
|
|
13
|
-
|
|
14
|
-
? {
|
|
15
|
-
|
|
13
|
+
const toolOptions = config.authMode === "cli"
|
|
14
|
+
? {
|
|
15
|
+
authMode: config.authMode,
|
|
16
|
+
workspaceSelection: config.workspaceSelection,
|
|
17
|
+
}
|
|
18
|
+
: { authMode: config.authMode };
|
|
19
|
+
registerHyperstarTools(server, createHyperstarClient({ config }), toolOptions);
|
|
16
20
|
return server;
|
|
17
21
|
}
|
package/dist/workspaces.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { CliWorkspaceSelection } from "./config.js";
|
|
1
|
+
import type { CliWorkspaceSelection, HyperstarMcpConfig } from "./config.js";
|
|
2
2
|
import type { HyperstarClient, JsonObject } from "./http.js";
|
|
3
3
|
export type WorkspaceToolOptions = {
|
|
4
|
+
readonly authMode?: HyperstarMcpConfig["authMode"];
|
|
4
5
|
readonly workspaceSelection?: CliWorkspaceSelection;
|
|
5
6
|
};
|
|
6
7
|
/** List workspaces through the Product API workspace route. */
|
package/dist/workspaces.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WorkspaceListResponseSchema } from "./schemas.js";
|
|
2
|
-
import { workflowGuideJson } from "./workflow-content.js";
|
|
2
|
+
import { CLI_SAFETY_NOTES, CLI_WORKFLOW_SEQUENCE, WORKFLOW_DATA_FLOW_NOTES, workflowGuideJson, workflowGuideResourceDefinitions, } from "./workflow-content.js";
|
|
3
3
|
/** List workspaces through the Product API workspace route. */
|
|
4
4
|
export async function listAvailableWorkspaces(client, options = {}) {
|
|
5
5
|
const payload = WorkspaceListResponseSchema.parse(await client.get("/v1/workspaces"));
|
|
@@ -33,6 +33,20 @@ export async function selectAvailableWorkspace(client, organizationId, options =
|
|
|
33
33
|
}
|
|
34
34
|
/** Return the recommended Hyperstar agent workflow and send-safety notes. */
|
|
35
35
|
export function getHyperstarWorkflowGuide(options = {}) {
|
|
36
|
+
if (options.authMode === "unauthenticated") {
|
|
37
|
+
return {
|
|
38
|
+
sequence: [
|
|
39
|
+
"Configure auth first: run `hyperstar login` and select a workspace, or set HYPERSTAR_API_KEY.",
|
|
40
|
+
...CLI_WORKFLOW_SEQUENCE,
|
|
41
|
+
],
|
|
42
|
+
safety_notes: [
|
|
43
|
+
"MCP tools and guides are discoverable before auth, but Product API workflow calls require local browser login or HYPERSTAR_API_KEY.",
|
|
44
|
+
...CLI_SAFETY_NOTES,
|
|
45
|
+
],
|
|
46
|
+
data_flow_notes: [...WORKFLOW_DATA_FLOW_NOTES],
|
|
47
|
+
resources: workflowGuideResourceDefinitions.map((resource) => resource.uri),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
36
50
|
if (options.workspaceSelection === undefined) {
|
|
37
51
|
return workflowGuideJson("service_account");
|
|
38
52
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperstar/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"description": "Local stdio MCP server and CLI for Hyperstar headless workflows.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"hyperstar",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"files": [
|
|
35
35
|
"dist",
|
|
36
36
|
"scripts/npm-clean-room-smoke.mjs",
|
|
37
|
+
"LICENSE",
|
|
37
38
|
"README.md",
|
|
38
39
|
"package.json"
|
|
39
40
|
],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
4
5
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
5
6
|
import { tmpdir } from "node:os";
|
|
6
7
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
@@ -39,11 +40,25 @@ function logLocalPackageSpec(value) {
|
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
function smokeEnv() {
|
|
44
|
+
const env = {
|
|
45
|
+
...process.env,
|
|
46
|
+
HOME: scratchDir,
|
|
47
|
+
XDG_CONFIG_HOME: resolve(scratchDir, "config"),
|
|
48
|
+
npm_config_cache: resolve(scratchDir, "npm-cache"),
|
|
49
|
+
npm_config_update_notifier: "false",
|
|
50
|
+
};
|
|
51
|
+
delete env.HYPERSTAR_API_KEY;
|
|
52
|
+
delete env.HYPERSTAR_API_BASE_URL;
|
|
53
|
+
delete env.HYPERSTAR_APP_BASE_URL;
|
|
54
|
+
return env;
|
|
55
|
+
}
|
|
56
|
+
|
|
42
57
|
function runStep(step, command, args) {
|
|
43
58
|
const result = spawnSync(command, args, {
|
|
44
59
|
cwd: scratchDir,
|
|
45
60
|
encoding: "utf8",
|
|
46
|
-
env:
|
|
61
|
+
env: smokeEnv(),
|
|
47
62
|
shell: false,
|
|
48
63
|
});
|
|
49
64
|
const stdout = result.stdout.trim();
|
|
@@ -79,6 +94,115 @@ function runStep(step, command, args) {
|
|
|
79
94
|
);
|
|
80
95
|
}
|
|
81
96
|
|
|
97
|
+
async function runMcpDiscoveryStep() {
|
|
98
|
+
const child = spawn(
|
|
99
|
+
"npm",
|
|
100
|
+
["exec", "--yes", "--package", packageSpec, "--", "hyperstar-mcp"],
|
|
101
|
+
{
|
|
102
|
+
cwd: scratchDir,
|
|
103
|
+
env: smokeEnv(),
|
|
104
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
const responses = [];
|
|
108
|
+
let stdout = "";
|
|
109
|
+
let stderr = "";
|
|
110
|
+
child.stdout.setEncoding("utf8");
|
|
111
|
+
child.stderr.setEncoding("utf8");
|
|
112
|
+
child.stdout.on("data", (chunk) => {
|
|
113
|
+
stdout += chunk;
|
|
114
|
+
for (;;) {
|
|
115
|
+
const lineEnd = stdout.indexOf("\n");
|
|
116
|
+
if (lineEnd === -1) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
const line = stdout.slice(0, lineEnd).trim();
|
|
120
|
+
stdout = stdout.slice(lineEnd + 1);
|
|
121
|
+
if (line.length === 0) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
responses.push(JSON.parse(line));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
child.stderr.on("data", (chunk) => {
|
|
128
|
+
stderr += chunk;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const send = (message) => {
|
|
132
|
+
child.stdin.write(`${JSON.stringify(message)}\n`);
|
|
133
|
+
};
|
|
134
|
+
const waitFor = (id) =>
|
|
135
|
+
new Promise((resolveResponse, rejectResponse) => {
|
|
136
|
+
const started = Date.now();
|
|
137
|
+
const interval = setInterval(() => {
|
|
138
|
+
const response = responses.find((item) => item.id === id);
|
|
139
|
+
if (response !== undefined) {
|
|
140
|
+
clearInterval(interval);
|
|
141
|
+
resolveResponse(response);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (Date.now() - started > 15_000) {
|
|
145
|
+
clearInterval(interval);
|
|
146
|
+
rejectResponse(
|
|
147
|
+
new Error(`Timed out waiting for MCP response ${id}: ${stderr}`),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}, 50);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
send({
|
|
155
|
+
jsonrpc: "2.0",
|
|
156
|
+
id: 1,
|
|
157
|
+
method: "initialize",
|
|
158
|
+
params: {
|
|
159
|
+
protocolVersion: "2024-11-05",
|
|
160
|
+
capabilities: {},
|
|
161
|
+
clientInfo: { name: "hyperstar-npm-smoke", version: "0.0.0" },
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
await waitFor(1);
|
|
165
|
+
send({ jsonrpc: "2.0", method: "notifications/initialized", params: {} });
|
|
166
|
+
send({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} });
|
|
167
|
+
send({ jsonrpc: "2.0", id: 3, method: "resources/list", params: {} });
|
|
168
|
+
send({ jsonrpc: "2.0", id: 4, method: "prompts/list", params: {} });
|
|
169
|
+
const [tools, resources, prompts] = await Promise.all([
|
|
170
|
+
waitFor(2),
|
|
171
|
+
waitFor(3),
|
|
172
|
+
waitFor(4),
|
|
173
|
+
]);
|
|
174
|
+
console.log(
|
|
175
|
+
JSON.stringify(
|
|
176
|
+
{
|
|
177
|
+
step: "hyperstar-mcp-discovery",
|
|
178
|
+
ok: true,
|
|
179
|
+
tools: tools.result.tools.map((tool) => tool.name).slice(0, 8),
|
|
180
|
+
resources: resources.result.resources.map((resource) => resource.uri),
|
|
181
|
+
prompts: prompts.result.prompts.map((prompt) => prompt.name),
|
|
182
|
+
},
|
|
183
|
+
null,
|
|
184
|
+
2,
|
|
185
|
+
),
|
|
186
|
+
);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error(
|
|
189
|
+
JSON.stringify(
|
|
190
|
+
{
|
|
191
|
+
step: "hyperstar-mcp-discovery",
|
|
192
|
+
ok: false,
|
|
193
|
+
error: error instanceof Error ? error.message : String(error),
|
|
194
|
+
stderr: stderr.trim(),
|
|
195
|
+
},
|
|
196
|
+
null,
|
|
197
|
+
2,
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
process.exitCode = 1;
|
|
201
|
+
} finally {
|
|
202
|
+
child.kill("SIGTERM");
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
82
206
|
try {
|
|
83
207
|
if (isLocalPackageSpec(packageSpec)) {
|
|
84
208
|
logLocalPackageSpec(packageSpec);
|
|
@@ -108,6 +232,7 @@ try {
|
|
|
108
232
|
"hyperstar-mcp",
|
|
109
233
|
"--help",
|
|
110
234
|
]);
|
|
235
|
+
await runMcpDiscoveryStep();
|
|
111
236
|
} finally {
|
|
112
237
|
rmSync(scratchDir, { recursive: true, force: true });
|
|
113
238
|
}
|