@clien-ai/mcp 0.1.0
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 +221 -0
- package/dist/auth/oauth.js +468 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/pkce.js +31 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/storage.js +371 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/cli.js +280 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/authorize.js +57 -0
- package/dist/commands/authorize.js.map +1 -0
- package/dist/commands/install.js +144 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/logout.js +35 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/status.js +70 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config.js +48 -0
- package/dist/config.js.map +1 -0
- package/dist/server.js +189 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/research.js +453 -0
- package/dist/tools/research.js.map +1 -0
- package/dist/types/report.js +60 -0
- package/dist/types/report.js.map +1 -0
- package/dist/util/atomic-write.js +43 -0
- package/dist/util/atomic-write.js.map +1 -0
- package/dist/util/exit-codes.js +97 -0
- package/dist/util/exit-codes.js.map +1 -0
- package/package.json +54 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration for @clien-ai/mcp.
|
|
3
|
+
*
|
|
4
|
+
* All values are environment-overridable so the package can be pointed at a
|
|
5
|
+
* local dev server or the test Supabase project during integration tests.
|
|
6
|
+
* Defaults are production.
|
|
7
|
+
*
|
|
8
|
+
* Client IDs are PUBLIC PKCE clients — no secret, safe to embed.
|
|
9
|
+
*/
|
|
10
|
+
const PROD_SUPABASE_URL = 'https://pnjwddgqxiohaziscoye.supabase.co';
|
|
11
|
+
const TEST_SUPABASE_URL = 'https://fudinhtlghtipznalrgy.supabase.co';
|
|
12
|
+
const PROD_CLIENT_ID = '9ab91ab2-844a-4b55-a54c-7f9765aa4aaa';
|
|
13
|
+
const TEST_CLIENT_ID = '7e40f4b2-c10d-4f51-a755-c05e513d3b96';
|
|
14
|
+
const DEFAULT_PORTS = [7873, 7874, 7875];
|
|
15
|
+
const DEFAULT_POLL_INTERVAL_MS = 5000;
|
|
16
|
+
const DEFAULT_OAUTH_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes to complete browser consent
|
|
17
|
+
function readEnv(name) {
|
|
18
|
+
const val = process.env[name];
|
|
19
|
+
return val && val.length > 0 ? val : undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build runtime config. Prefers env vars (for dev/test), falls back to prod
|
|
23
|
+
* defaults. Switching to test mode: set CLIEN_MCP_ENV=test.
|
|
24
|
+
*/
|
|
25
|
+
export function loadConfig() {
|
|
26
|
+
const env = (readEnv('CLIEN_MCP_ENV') ?? 'prod').toLowerCase();
|
|
27
|
+
const isTest = env === 'test';
|
|
28
|
+
const serverUrl = readEnv('CLIEN_MCP_SERVER_URL') ??
|
|
29
|
+
(isTest ? 'https://clien.ai' : 'https://clien.ai');
|
|
30
|
+
const supabaseUrl = readEnv('CLIEN_MCP_SUPABASE_URL') ??
|
|
31
|
+
(isTest ? TEST_SUPABASE_URL : PROD_SUPABASE_URL);
|
|
32
|
+
const clientId = readEnv('CLIEN_MCP_CLIENT_ID') ??
|
|
33
|
+
(isTest ? TEST_CLIENT_ID : PROD_CLIENT_ID);
|
|
34
|
+
const pollEnv = readEnv('CLIEN_MCP_POLL_INTERVAL_MS');
|
|
35
|
+
const pollIntervalMs = pollEnv ? Math.max(500, Number(pollEnv)) : DEFAULT_POLL_INTERVAL_MS;
|
|
36
|
+
return {
|
|
37
|
+
serverUrl: serverUrl.replace(/\/$/, ''),
|
|
38
|
+
supabaseUrl: supabaseUrl.replace(/\/$/, ''),
|
|
39
|
+
clientId,
|
|
40
|
+
scope: readEnv('CLIEN_MCP_SCOPE') ?? 'openid',
|
|
41
|
+
oauthPorts: DEFAULT_PORTS,
|
|
42
|
+
pollIntervalMs,
|
|
43
|
+
oauthTimeoutMs: DEFAULT_OAUTH_TIMEOUT_MS,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export const PACKAGE_NAME = '@clien-ai/mcp';
|
|
47
|
+
export const PACKAGE_VERSION = '0.1.0';
|
|
48
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmBH,MAAM,iBAAiB,GAAG,0CAA0C,CAAA;AACpE,MAAM,iBAAiB,GAAG,0CAA0C,CAAA;AAEpE,MAAM,cAAc,GAAG,sCAAsC,CAAA;AAC7D,MAAM,cAAc,GAAG,sCAAsC,CAAA;AAE7D,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AACjD,MAAM,wBAAwB,GAAG,IAAI,CAAA;AACrC,MAAM,wBAAwB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,wCAAwC;AAEvF,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;IAC9D,MAAM,MAAM,GAAG,GAAG,KAAK,MAAM,CAAA;IAE7B,MAAM,SAAS,GACb,OAAO,CAAC,sBAAsB,CAAC;QAC/B,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAA;IACpD,MAAM,WAAW,GACf,OAAO,CAAC,wBAAwB,CAAC;QACjC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAA;IAClD,MAAM,QAAQ,GACZ,OAAO,CAAC,qBAAqB,CAAC;QAC9B,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAA;IAE5C,MAAM,OAAO,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAA;IACrD,MAAM,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAA;IAE1F,OAAO;QACL,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACvC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QAC3C,QAAQ;QACR,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,IAAI,QAAQ;QAC7C,UAAU,EAAE,aAAa;QACzB,cAAc;QACd,cAAc,EAAE,wBAAwB;KACzC,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,eAAe,CAAA;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAA"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP stdio server entry point.
|
|
3
|
+
*
|
|
4
|
+
* Registers the `clien_research` tool. Auth happens lazily on first tool call
|
|
5
|
+
* so the server can announce its tool list without a browser interruption.
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
8
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
9
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
10
|
+
import { loadConfig, PACKAGE_NAME, PACKAGE_VERSION } from './config.js';
|
|
11
|
+
import { ensureSession, } from './auth/oauth.js';
|
|
12
|
+
import { clearTokens, loadRefreshToken, saveRefreshToken, withTokenLock, } from './auth/storage.js';
|
|
13
|
+
import { ResearchToolError, runResearch, } from './tools/research.js';
|
|
14
|
+
function log(...args) {
|
|
15
|
+
// stderr only — stdout is the MCP transport.
|
|
16
|
+
console.error('[clien-mcp]', ...args);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Default browser opener — lazily imports `open` so the package still loads
|
|
20
|
+
* on systems that can't open a browser (we handle the error in OAuth).
|
|
21
|
+
*/
|
|
22
|
+
async function defaultBrowserOpener() {
|
|
23
|
+
const mod = (await import('open'));
|
|
24
|
+
const fn = typeof mod === 'function'
|
|
25
|
+
? mod
|
|
26
|
+
: mod.default;
|
|
27
|
+
return async (url) => {
|
|
28
|
+
await fn(url);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Input schema for the tool advert. Hand-rolled JSON Schema so we avoid the
|
|
33
|
+
* `zod-to-json-schema` dependency. Must stay in sync with `ResearchInputSchema`
|
|
34
|
+
* in `src/tools/research.ts` — the Zod parser is still the source of truth at
|
|
35
|
+
* runtime; this is only the spec advertised to the caller.
|
|
36
|
+
*
|
|
37
|
+
* Drift surfaces silently: the Zod parser still accepts the input, but strict
|
|
38
|
+
* MCP clients (`additionalProperties: false`) strip undeclared fields before
|
|
39
|
+
* they reach the parser, and LLM callers never learn the field exists.
|
|
40
|
+
* Enforcement: `__tests__/schema-contract.test.ts` walks both schemas and
|
|
41
|
+
* fails if their property keys or required-field sets diverge. Exported here
|
|
42
|
+
* so that test can import it. See
|
|
43
|
+
* `docs/solutions/design-patterns/cross-package-schema-duplication-contract-2026-05-12.md`.
|
|
44
|
+
*/
|
|
45
|
+
export const RESEARCH_INPUT_SCHEMA = {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
idea: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
minLength: 1,
|
|
51
|
+
maxLength: 10_000,
|
|
52
|
+
description: 'The product idea, feature hypothesis, or research question to validate. ' +
|
|
53
|
+
'Can be a one-liner or several paragraphs — more context yields a better report.',
|
|
54
|
+
},
|
|
55
|
+
depth: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
enum: ['quick', 'deep'],
|
|
58
|
+
default: 'deep',
|
|
59
|
+
description: '"deep" (default) runs a 15-25 minute full research pass. ' +
|
|
60
|
+
'"quick" caps cost and runs a tighter pass.',
|
|
61
|
+
},
|
|
62
|
+
project_id: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
format: 'uuid',
|
|
65
|
+
description: 'Optional Clien.ai project UUID to attach this run to. When omitted, ' +
|
|
66
|
+
'the run is standalone and not associated with any project.',
|
|
67
|
+
},
|
|
68
|
+
project_name: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
minLength: 1,
|
|
71
|
+
maxLength: 100,
|
|
72
|
+
description: 'Name for a new Clien.ai project to attach this run to. You SHOULD ' +
|
|
73
|
+
'supply this whenever `project_id` is not set, otherwise the ' +
|
|
74
|
+
'resulting report will not be discoverable in the Clien.ai web UI. ' +
|
|
75
|
+
'Derive a short (2-4 word) human-readable name from the idea — ' +
|
|
76
|
+
'typically the product name. Guidance on when to create a new ' +
|
|
77
|
+
'project vs. reuse an existing one: create a NEW project (supply a ' +
|
|
78
|
+
'fresh `project_name`) for each distinct research idea or product ' +
|
|
79
|
+
'concept; REUSE an existing `project_id` only when the user ' +
|
|
80
|
+
'explicitly asks to add follow-up research to a prior run on the ' +
|
|
81
|
+
'same idea. Ignored when `project_id` is also provided.',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
required: ['idea'],
|
|
85
|
+
additionalProperties: false,
|
|
86
|
+
};
|
|
87
|
+
export function createMcpServer() {
|
|
88
|
+
const config = loadConfig();
|
|
89
|
+
// Per-instance session cache. Scoping this to the closure (rather than the
|
|
90
|
+
// module) means each `createMcpServer()` call gets its own cache, so tests
|
|
91
|
+
// that build a fresh server per case start cold without any shared-state
|
|
92
|
+
// gymnastics. In production we only ever construct one server per process
|
|
93
|
+
// (`startStdioServer`), so behavior is identical.
|
|
94
|
+
let cachedSession = null;
|
|
95
|
+
async function getSession() {
|
|
96
|
+
if (cachedSession)
|
|
97
|
+
return cachedSession;
|
|
98
|
+
const opener = await defaultBrowserOpener();
|
|
99
|
+
cachedSession = await ensureSession({
|
|
100
|
+
config,
|
|
101
|
+
loadRefreshToken,
|
|
102
|
+
saveRefreshToken,
|
|
103
|
+
clearTokens,
|
|
104
|
+
openBrowser: opener,
|
|
105
|
+
withTokenLock,
|
|
106
|
+
});
|
|
107
|
+
return cachedSession;
|
|
108
|
+
}
|
|
109
|
+
// Invalidate the in-memory session so the next tool call rebuilds it from
|
|
110
|
+
// disk. Called from the polling loop when a 401 indicates server-side
|
|
111
|
+
// revocation — without this, a long-lived MCP process would keep using the
|
|
112
|
+
// cached (now-invalid) access token until process restart. See issue #168.
|
|
113
|
+
function invalidateSession() {
|
|
114
|
+
cachedSession = null;
|
|
115
|
+
}
|
|
116
|
+
const server = new Server({ name: PACKAGE_NAME, version: PACKAGE_VERSION }, { capabilities: { tools: {} } });
|
|
117
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
118
|
+
tools: [
|
|
119
|
+
{
|
|
120
|
+
name: 'clien_research',
|
|
121
|
+
description: 'Run a full product-research pass on an idea. Returns a markdown report plus ' +
|
|
122
|
+
'structured report_data (hypotheses, competitors[], key findings). Typical wall time ' +
|
|
123
|
+
'15-25 minutes; progress is streamed via notifications/progress. ' +
|
|
124
|
+
'First call opens a browser for one-time OAuth login; subsequent calls reuse the stored refresh token.',
|
|
125
|
+
inputSchema: RESEARCH_INPUT_SCHEMA,
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
}));
|
|
129
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
130
|
+
if (request.params.name !== 'clien_research') {
|
|
131
|
+
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
132
|
+
}
|
|
133
|
+
// Per MCP spec, `progressToken` may be a string OR a number, and `0` or
|
|
134
|
+
// `''` are valid token values. A truthy check (`progressToken ?`) silently
|
|
135
|
+
// drops progress for those callers. Compare against `undefined` instead.
|
|
136
|
+
const progressToken = request.params._meta?.progressToken;
|
|
137
|
+
const onProgress = progressToken !== undefined
|
|
138
|
+
? async (progress) => {
|
|
139
|
+
try {
|
|
140
|
+
await server.notification({
|
|
141
|
+
method: 'notifications/progress',
|
|
142
|
+
params: {
|
|
143
|
+
progressToken,
|
|
144
|
+
progress: progress.progress,
|
|
145
|
+
total: progress.total,
|
|
146
|
+
message: progress.message,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
log('progress notification failed:', err);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
: undefined;
|
|
155
|
+
try {
|
|
156
|
+
const session = await getSession();
|
|
157
|
+
const result = await runResearch(request.params.arguments, {
|
|
158
|
+
config,
|
|
159
|
+
session,
|
|
160
|
+
onProgress,
|
|
161
|
+
invalidateSession,
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
content: result.content,
|
|
165
|
+
_meta: result._meta,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
const message = err instanceof ResearchToolError
|
|
170
|
+
? err.userMessage
|
|
171
|
+
: err instanceof Error
|
|
172
|
+
? err.message
|
|
173
|
+
: String(err);
|
|
174
|
+
log('tool error:', message);
|
|
175
|
+
return {
|
|
176
|
+
isError: true,
|
|
177
|
+
content: [{ type: 'text', text: message }],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return server;
|
|
182
|
+
}
|
|
183
|
+
export async function startStdioServer() {
|
|
184
|
+
const server = createMcpServer();
|
|
185
|
+
const transport = new StdioServerTransport();
|
|
186
|
+
await server.connect(transport);
|
|
187
|
+
log(`connected on stdio — ${PACKAGE_NAME}@${PACKAGE_VERSION}`);
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|