@biomate/mcp-server 0.1.0 → 0.1.1
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 +12 -6
- package/dist/auth.d.ts +8 -0
- package/dist/auth.js +54 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -4
- package/dist/tools_manifest.json +197 -948
- package/package.json +16 -4
package/README.md
CHANGED
|
@@ -27,19 +27,19 @@ Get your API key at **[dev-public.biomate.ai/account/api-keys](https://dev-publi
|
|
|
27
27
|
|
|
28
28
|
| Tool | Purpose |
|
|
29
29
|
|---|---|
|
|
30
|
-
| `biomate_session` |
|
|
31
|
-
| `search_workflow` | Search
|
|
30
|
+
| `biomate_session` | Plan an analysis and return workflow suggestions and clarification requests |
|
|
31
|
+
| `search_workflow` | Search the workflow catalog by natural language |
|
|
32
32
|
| `get_workflow_spec` | Full parameter spec for a workflow |
|
|
33
33
|
| `run_workflow` | Execute with explicit parameters |
|
|
34
|
-
| `get_run` / `watch_run` | Status
|
|
34
|
+
| `get_run` / `watch_run` | Status snapshots, outputs and available findings |
|
|
35
35
|
| `cancel_run` | Cancel a running job |
|
|
36
36
|
| `list_runs` | History with filters |
|
|
37
37
|
| `preview_file` | Server-side preview of output files |
|
|
38
|
-
| `export_report` |
|
|
38
|
+
| `export_report` | Markdown findings report (may return pending during preparation) |
|
|
39
39
|
| `analyze_results` | AI interpretation of findings |
|
|
40
40
|
| `explain_error` | Root-cause diagnosis for failed runs |
|
|
41
41
|
| `query_database` | UniProt, PDB, NCBI, ChEMBL, AlphaFold |
|
|
42
|
-
| `resolve_accession` |
|
|
42
|
+
| `resolve_accession` | Resolve a public accession |
|
|
43
43
|
| `browse_data` / `fetch_public_data` | Browse and stage public datasets |
|
|
44
44
|
| `upload_file` | Get signed S3 PUT URL for local uploads |
|
|
45
45
|
| `recall_memory` | Retrieve relevant prior runs and procedures |
|
|
@@ -49,7 +49,7 @@ Get your API key at **[dev-public.biomate.ai/account/api-keys](https://dev-publi
|
|
|
49
49
|
|
|
50
50
|
| Variable | Description |
|
|
51
51
|
|---|---|
|
|
52
|
-
| `BIOMATE_API_KEY` | Personal API key (`bm_live_xxx`) —
|
|
52
|
+
| `BIOMATE_API_KEY` | Personal API key (`bm_live_xxx`) — alternative to OAuth |
|
|
53
53
|
| `BIOMATE_API_BASE` | BioMate server URL (default: `https://dev-public.biomate.ai`) |
|
|
54
54
|
|
|
55
55
|
## Example
|
|
@@ -69,3 +69,9 @@ Get your API key at **[dev-public.biomate.ai/account/api-keys](https://dev-publi
|
|
|
69
69
|
## License
|
|
70
70
|
|
|
71
71
|
MIT — this package only. BioMate platform usage governed by [biomate.ai/terms](https://biomate.ai/terms).
|
|
72
|
+
|
|
73
|
+
## OAuth sign-in (0.1.1)
|
|
74
|
+
|
|
75
|
+
Run `npx @biomate/connect@0.1.1 claude-code --auth-base https://dev-public.biomate.ai` (or use `claude-desktop`, `cursor`, or `codex`). This explicitly selects the development deployment. The installer stores a protected credential file and sets `BIOMATE_OAUTH_FILE` in the host configuration. The client refreshes and persists rotating tokens and calls the OAuth gateway using the current user identity. Existing OAuth installations must reconnect; a refresh token is never used as a personal API key.
|
|
76
|
+
|
|
77
|
+
This package has 19 tools. Instrument tools, PDF/DOCX exports, automatic session execution and progress notifications are not supported by this stdio adapter. Use `get_run` to poll status and export Markdown findings.
|
package/dist/auth.d.ts
ADDED
package/dist/auth.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
function origin(value) {
|
|
4
|
+
const url = new URL(value);
|
|
5
|
+
if (url.protocol !== 'https:' && !(url.protocol === 'http:' && ['127.0.0.1', 'localhost'].includes(url.hostname)))
|
|
6
|
+
throw new Error('OAuth requires HTTPS');
|
|
7
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== '/')
|
|
8
|
+
throw new Error('OAuth base must be an origin');
|
|
9
|
+
return url.origin;
|
|
10
|
+
}
|
|
11
|
+
export async function oauthCredential(file) {
|
|
12
|
+
const lock = file + '.lock';
|
|
13
|
+
let handle;
|
|
14
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
15
|
+
try {
|
|
16
|
+
handle = await fs.open(lock, 'wx', 0o600);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error.code !== 'EEXIST')
|
|
21
|
+
throw error;
|
|
22
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (!handle)
|
|
26
|
+
throw new Error('OAuth credentials locked; retry or reconnect BioMate');
|
|
27
|
+
try {
|
|
28
|
+
const current = JSON.parse(await fs.readFile(file, 'utf8'));
|
|
29
|
+
current.authBase = origin(current.authBase);
|
|
30
|
+
if (!current.clientId || !current.refresh_token)
|
|
31
|
+
throw new Error('Reconnect BioMate: incomplete OAuth credentials');
|
|
32
|
+
if (current.access_token && current.expires_at > Date.now() + 60000)
|
|
33
|
+
return current;
|
|
34
|
+
const response = await fetch(current.authBase + '/oauth/token', {
|
|
35
|
+
method: 'POST', redirect: 'error', signal: AbortSignal.timeout(15000),
|
|
36
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
37
|
+
body: new URLSearchParams({ grant_type: 'refresh_token', client_id: current.clientId, refresh_token: current.refresh_token }),
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok)
|
|
40
|
+
throw new Error(`OAuth refresh failed (HTTP ${response.status}); reconnect BioMate`);
|
|
41
|
+
const updated = await response.json();
|
|
42
|
+
if (!updated.access_token || !updated.refresh_token || !(Number(updated.expires_in) > 0))
|
|
43
|
+
throw new Error('Invalid OAuth token response; reconnect BioMate');
|
|
44
|
+
const next = { ...current, access_token: updated.access_token, refresh_token: updated.refresh_token, expires_at: Date.now() + Number(updated.expires_in) * 1000 };
|
|
45
|
+
const tmp = file + '.' + randomUUID() + '.tmp';
|
|
46
|
+
await fs.writeFile(tmp, JSON.stringify(next), { mode: 0o600 });
|
|
47
|
+
await fs.rename(tmp, file);
|
|
48
|
+
return next;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
await handle.close();
|
|
52
|
+
await fs.unlink(lock);
|
|
53
|
+
}
|
|
54
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Configuration (environment variables):
|
|
9
9
|
* BIOMATE_API_BASE BioMate server URL (default: https://dev-public.biomate.ai)
|
|
10
10
|
* BIOMATE_API_KEY Personal API key (bm_live_xxx) from biomate.ai/account/api-keys
|
|
11
|
-
*
|
|
11
|
+
* BIOMATE_OAUTH_FILE Protected credential file written by @biomate/connect
|
|
12
12
|
*
|
|
13
13
|
* Each tool call POSTs to ${BIOMATE_API_BASE}/tools/${toolName} with the
|
|
14
14
|
* Authorization header set. The /tools/* routes are served by BioMate's
|
package/dist/index.js
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
* Configuration (environment variables):
|
|
9
9
|
* BIOMATE_API_BASE BioMate server URL (default: https://dev-public.biomate.ai)
|
|
10
10
|
* BIOMATE_API_KEY Personal API key (bm_live_xxx) from biomate.ai/account/api-keys
|
|
11
|
-
*
|
|
11
|
+
* BIOMATE_OAUTH_FILE Protected credential file written by @biomate/connect
|
|
12
12
|
*
|
|
13
13
|
* Each tool call POSTs to ${BIOMATE_API_BASE}/tools/${toolName} with the
|
|
14
14
|
* Authorization header set. The /tools/* routes are served by BioMate's
|
|
15
15
|
* Node.js API server.
|
|
16
16
|
*/
|
|
17
|
+
import { oauthCredential } from "./auth.js";
|
|
17
18
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
18
19
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
20
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -21,7 +22,7 @@ import { createRequire } from "module";
|
|
|
21
22
|
const require = createRequire(import.meta.url);
|
|
22
23
|
// ── Config ────────────────────────────────────────────────────────────────────
|
|
23
24
|
const API_BASE = (process.env.BIOMATE_API_BASE ?? "https://dev-public.biomate.ai").replace(/\/$/, "");
|
|
24
|
-
const API_KEY = process.env.BIOMATE_API_KEY ??
|
|
25
|
+
const API_KEY = process.env.BIOMATE_API_KEY ?? "";
|
|
25
26
|
// ── Tools manifest ────────────────────────────────────────────────────────────
|
|
26
27
|
const manifest = require("./tools_manifest.json");
|
|
27
28
|
const TOOLS = manifest.mcp.map((t) => ({
|
|
@@ -43,7 +44,18 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
43
44
|
let data;
|
|
44
45
|
let ok = true;
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
+
if (!TOOLS.some(tool => tool.name === name))
|
|
48
|
+
throw new Error("Unknown tool");
|
|
49
|
+
let endpoint = `${API_BASE}/tools/${name}`;
|
|
50
|
+
if (!API_KEY) {
|
|
51
|
+
if (!process.env.BIOMATE_OAUTH_FILE)
|
|
52
|
+
throw new Error("Reconnect BioMate with the updated installer or configure a personal API key");
|
|
53
|
+
const credential = await oauthCredential(process.env.BIOMATE_OAUTH_FILE);
|
|
54
|
+
headers.Authorization = `Bearer ${credential.access_token}`;
|
|
55
|
+
endpoint = `${credential.authBase}/oauth/tools/${name}`;
|
|
56
|
+
}
|
|
57
|
+
const res = await fetch(endpoint, {
|
|
58
|
+
redirect: "error",
|
|
47
59
|
method: "POST",
|
|
48
60
|
headers,
|
|
49
61
|
body: JSON.stringify(args ?? {}),
|
|
@@ -69,7 +81,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
69
81
|
};
|
|
70
82
|
});
|
|
71
83
|
// ── Start ─────────────────────────────────────────────────────────────────────
|
|
72
|
-
if (!API_KEY) {
|
|
84
|
+
if (!API_KEY && !process.env.BIOMATE_OAUTH_FILE) {
|
|
73
85
|
process.stderr.write("[biomate-mcp] WARNING: BIOMATE_API_KEY not set. " +
|
|
74
86
|
"Get your key at https://dev-public.biomate.ai/account/api-keys\n");
|
|
75
87
|
}
|