@yugabytedb/meko-mcp 2.5.0 → 2.5.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 +19 -5
- package/assets/hooks-handlers/lib/capture.js +1 -0
- package/assets/skills/meko-mcp-tools/SKILL.md +3 -2
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +3 -3
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +1 -1
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +2 -2
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +2 -2
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +4 -4
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +4 -2
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +4 -3
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +3 -3
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +2 -2
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +2 -2
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +4 -4
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +4 -3
- package/bin/create-meko-setup.mjs +48 -24
- package/lib/clients/codex.mjs +1 -24
- package/lib/clients/common.mjs +25 -0
- package/lib/migrate.mjs +1 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,8 +16,11 @@ through `mcp-remote` header interpolation. Capture hooks use the same key.
|
|
|
16
16
|
You don't need to have a key already. The installer gets one in this order:
|
|
17
17
|
|
|
18
18
|
1. `--api-key <key>`.
|
|
19
|
-
2. The `MEKO_API_KEY` environment variable
|
|
20
|
-
|
|
19
|
+
2. The `MEKO_API_KEY` environment variable, for any MCP URL, local ones
|
|
20
|
+
included. `--local` ignores it, and so does a `--yes` rerun that reuses the
|
|
21
|
+
URL an earlier `--local` install registered: the docker-compose dev stack
|
|
22
|
+
takes no key.
|
|
23
|
+
3. **Browser sign-in (the default, Cloud only).** The installer opens the Meko sign-in page,
|
|
21
24
|
and after you sign in it creates a key named `Meko installer (<host>)
|
|
22
25
|
<timestamp>`. It uses the MCP server's OAuth flow with a `localhost`
|
|
23
26
|
callback, then calls the server's `POST /api-keys`. The OAuth session is
|
|
@@ -170,6 +173,17 @@ npx @yugabytedb/meko-mcp \
|
|
|
170
173
|
--yes
|
|
171
174
|
```
|
|
172
175
|
|
|
176
|
+
**Meko Local (the `meko` server, which requires its client token):**
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
MEKO_API_KEY="$(meko token)" npx @yugabytedb/meko-mcp \
|
|
180
|
+
--url http://127.0.0.1:7778/mcp \
|
|
181
|
+
--yes
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Passing the key through `MEKO_API_KEY` keeps it off the command line, where
|
|
185
|
+
`ps` would show it.
|
|
186
|
+
|
|
173
187
|
## What It Does
|
|
174
188
|
|
|
175
189
|
The installer performs up to 5 steps (some are skippable via flags):
|
|
@@ -256,9 +270,9 @@ Usage:
|
|
|
256
270
|
|------|-------------|---------|
|
|
257
271
|
| `--client <list>` | Target client(s): one or more of `claude-code`, `claude-desktop`, `cursor`, `codex`, `kiro`, `opencode`. Comma-separated, or `all`. `codex` covers both the OpenAI Codex CLI and the Codex Desktop App (they share `~/.codex/config.toml`); `kiro` covers both the Kiro IDE and `kiro-cli` (they share `~/.kiro/settings/mcp.json`). OpenCode is version-gated to CLI/TUI 1.18.x. Aliases: `claude` → `claude-code`, `kiro-cli` / `kiro-ide` → `kiro`. | `claude-code` |
|
|
258
272
|
| `--url <url>` | MCP server URL (from cloud.mekodata.ai > Datapacks > Connect) | Shared existing endpoint, otherwise production; conflicts prompt or require `--url` under `--yes` |
|
|
259
|
-
| `--api-key <key>` | Use an existing
|
|
273
|
+
| `--api-key <key>` | Use an existing Meko API key (Cloud, or Meko Local's client token) instead of signing in. Without this flag, the installer falls back to `$MEKO_API_KEY` for any URL (not with `--local`), then, for Cloud URLs only, to browser sign-in, which creates a key. A Cloud URL with no key fails hard when no TTY is attached, with or without `--yes`; a local URL installs without one. | _(`$MEKO_API_KEY`, else browser sign-in for Cloud)_ |
|
|
260
274
|
| `--no-browser` | Print the sign-in URL instead of opening a browser. | `false` |
|
|
261
|
-
| `--local` | Use local Meko at `http://localhost:8000/mcp` (no API key
|
|
275
|
+
| `--local` | Use local Meko at `http://localhost:8000/mcp` (no API key; ignores `$MEKO_API_KEY`) | `false` |
|
|
262
276
|
| `--scope <scope>` | Config scope: `user` or `project` (`claude-desktop` uses user scope config) | `user` |
|
|
263
277
|
| `--name <name>` | MCP server name in config | `meko` |
|
|
264
278
|
| `--cursor-hook-mode <mode>` | Cursor hook strategy: `native` or `claude-compat` | `native` |
|
|
@@ -351,7 +365,7 @@ Dry run:
|
|
|
351
365
|
|
|
352
366
|
### Why the migrator drives memory extraction
|
|
353
367
|
|
|
354
|
-
The Meko MCP server does **not** currently auto-extract memories on `conversation_add_message` (that call only writes to Langfuse). See [yugabyte/
|
|
368
|
+
The Meko MCP server does **not** currently auto-extract memories on `conversation_add_message` (that call only writes to Langfuse). See [yugabyte/agentic-cloud#120](https://github.com/yugabyte/agentic-cloud/issues/120) — auto-extraction on the live write path was deferred because of LLM cost, but batch extraction for *previously-existing* conversations was explicitly endorsed. Until #120 lands, the migrator closes that gap itself by calling `memory_add(messages=...)` once per paired turn.
|
|
355
369
|
|
|
356
370
|
`--no-extract` skips step 3 above, turning migration into conversation-only replay. Use it when you're re-running for any reason other than seeding memories, when extraction cost is a concern, or if / when #120 lands (the migrator will be updated to default to `--no-extract` then).
|
|
357
371
|
|
|
@@ -2007,6 +2007,7 @@ function peekTranscriptMetadata(transcriptPath) {
|
|
|
2007
2007
|
async function fetchRecentMemories(agentId, datapackId = null, { limit = 10, budget = 2000 } = {}) {
|
|
2008
2008
|
// memory_get_all takes no `limit`, and FastMCP rejects an unknown argument
|
|
2009
2009
|
// with an isError result, so `limit` caps the page client-side instead.
|
|
2010
|
+
// Don't send `page_size` either: a server older than MEKO-453 rejects it.
|
|
2010
2011
|
const payload = {
|
|
2011
2012
|
agent_id: agentId,
|
|
2012
2013
|
conversation_id: "00000000-0000-0000-0000-000000000000",
|
|
@@ -4,7 +4,7 @@ description: Behavioral guide for AI agents using Meko MCP tools. Triggers when
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: Meko
|
|
7
|
-
version: "3.
|
|
7
|
+
version: "3.5.0"
|
|
8
8
|
tags: mcp, tools, datapack, memory, conversation, rag, meko
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -102,7 +102,8 @@ Recall first; save only what capture cannot reach; never re-store a just-stated
|
|
|
102
102
|
| User asks "what do we (as a team) know about X?" or about uploaded documents | `knowledgebase_search` (returns uploaded docs + promoted memories). |
|
|
103
103
|
| User asks to share private memories | Follow the exact-ID `memory_promote` confirmation workflow below. |
|
|
104
104
|
| User provides structured/tabular data (CSV, data dictionary) | If it's an actual file the user wants in the team's knowledge base, `knowledgebase_upload_document` accepts `.csv` directly (confirm first; see below). If it's pasted/described data with no file behind it, still don't `memory_add` it row-by-row — ask the user for it as a file, or point them at the UI's Add Knowledge upload. |
|
|
105
|
-
| User wants
|
|
105
|
+
| User wants a file kept in Meko but didn't say how | KB (`knowledgebase_upload_document`) if its content should be searchable later — docs, manuals, policies, notes people will ask about. Artifact (`artifact_put`) to keep it exactly as-is and fetch it back whole — a generated report, a result CSV. If it is not clear whether the user needs semantic search or whole-file retrieval, ask. |
|
|
106
|
+
| User wants to add documents to the team's knowledge base | Uploading adds the file to the datapack's shared knowledge base, which every member can read, so ask first: name the file and the datapack, say the team will see it, and upload only after the user says yes. If you have the file's bytes — already on disk, or generated mid-conversation — and a shell, check that you can reach S3 first: run `curl -sS -o /dev/null -m 10 -w '%{http_code}' https://s3.amazonaws.com`; in Windows PowerShell, run `curl.exe` with `NUL` in place of `/dev/null`. A 2xx or 3xx status means yes (S3's root normally answers 307). `000`, a connection, DNS or proxy error, or any other status, such as a proxy's 403 or 407, means no. A pass shows outbound HTTPS to S3 works, not that the presigned bucket host does, so if the POST still fails, report it and stop. If it passes, call `knowledgebase_upload_document`. A sandboxed session may have the file but no outbound network; if the check fails, don't call it, since an unused URL holds storage quota for up to 15 minutes. Otherwise point the user at the Cloud UI flow — Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch). KB *lifecycle* (index/source management) is still UI-only. |
|
|
106
107
|
|
|
107
108
|
### When to call memory_add
|
|
108
109
|
|
|
@@ -296,7 +296,7 @@ Returns `{"document_id", "chunks_deleted", "s3_deleted"}` — if `s3_deleted` is
|
|
|
296
296
|
|
|
297
297
|
### knowledgebase_upload_document
|
|
298
298
|
|
|
299
|
-
**When to use:** Get a file's bytes into the datapack's KB for later `knowledgebase_search` retrieval — a file already on disk, or one generated mid-conversation. This tool never touches the file's bytes itself; it only requests a presigned S3 URL. Meko registers the file once it lands, so there's no separate confirm call. **The caller POSTs the file to the returned `url` directly** — multipart/form-data, every key in `fields` as a form field (in order), then the file's bytes last as a field named `"file"`.
|
|
299
|
+
**When to use:** Get a file's bytes into the datapack's KB for later `knowledgebase_search` retrieval — a file already on disk, or one generated mid-conversation. Use it when the content should be searchable by meaning; to keep a file exactly as-is and fetch it back whole, use `artifact_put`. Before calling it, check that you can reach S3 first: run `curl -sS -o /dev/null -m 10 -w '%{http_code}' https://s3.amazonaws.com`; in Windows PowerShell, run `curl.exe` with `NUL` in place of `/dev/null`. A 2xx or 3xx status means yes (S3's root normally answers 307). `000`, a connection, DNS or proxy error, or any other status, such as a proxy's 403 or 407, means no. A pass shows outbound HTTPS to S3 works, not that the presigned bucket host does, so if the POST still fails, report it and stop; a sandboxed session may have the file but no outbound network. If the check fails, don't call it — point the user at the UI. This tool never touches the file's bytes itself; it only requests a presigned S3 URL. Meko registers the file once it lands, so there's no separate confirm call. **The caller POSTs the file to the returned `url` directly** — multipart/form-data, every key in `fields` as a form field (in order), then the file's bytes last as a field named `"file"`.
|
|
300
300
|
|
|
301
301
|
**Confirm first.** The file goes into the datapack's shared knowledge base, which every member can read. Before calling the tool, tell the user which file and datapack, say the team will see it, and wait for a yes.
|
|
302
302
|
|
|
@@ -465,7 +465,7 @@ Poll until `state` is `completed` or `failed` (or the pre-registration terminals
|
|
|
465
465
|
|
|
466
466
|
### artifact_put
|
|
467
467
|
|
|
468
|
-
**When to use:** An agent has generated a file (report, CSV, PDF, code output, image) and wants to persist it in Meko for later retrieval or cross-agent sharing. Files < 1 MB are stored inline in the DB; files ≥ 1 MB go to the datapack's S3 bucket. Idempotent — uploading the same bytes twice returns the same `content_hash`.
|
|
468
|
+
**When to use:** An agent has generated a file (report, CSV, PDF, code output, image) and wants to persist it in Meko for later retrieval or cross-agent sharing. To make its content searchable by meaning instead, use `knowledgebase_upload_document`. Files < 1 MB are stored inline in the DB; files ≥ 1 MB go to the datapack's S3 bucket. Idempotent — uploading the same bytes twice returns the same `content_hash`.
|
|
469
469
|
|
|
470
470
|
```
|
|
471
471
|
artifact_put(
|
|
@@ -604,4 +604,4 @@ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/li
|
|
|
604
604
|
- REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
|
|
605
605
|
- Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
|
|
606
606
|
|
|
607
|
-
Uploading a *file* into an existing KB is not part of that lifecycle restriction — use `knowledgebase_upload_document` (see above) rather than the UI for anything driven from MCP. Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
|
|
607
|
+
Uploading a *file* into an existing KB is not part of that lifecycle restriction — use `knowledgebase_upload_document` (see above) rather than the UI for anything driven from MCP, when you can POST the file's bytes yourself. Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
|
|
@@ -35,7 +35,7 @@ Provisioning agents and knowledge-base *sources* (registering/indexing a new sou
|
|
|
35
35
|
|
|
36
36
|
If the user asks to set those up mid-session, point them at the control plane rather than inventing an MCP call that will fail.
|
|
37
37
|
|
|
38
|
-
Uploading a *file* into an existing KB is a different, already-MCP-exposed operation — use `knowledgebase_upload_document` (see `tools-cookbook.md`) rather than routing the user to the Add Knowledge UI.
|
|
38
|
+
Uploading a *file* into an existing KB is a different, already-MCP-exposed operation — use `knowledgebase_upload_document` (see `tools-cookbook.md`) rather than routing the user to the Add Knowledge UI, when you can POST the file's bytes yourself.
|
|
39
39
|
|
|
40
40
|
### Targeting a specific datapack on subsequent calls
|
|
41
41
|
|
|
@@ -60,7 +60,7 @@ The one exception is a single uploaded **file**: `knowledgebase_delete_document`
|
|
|
60
60
|
|
|
61
61
|
Manually creating a vector index, adding a source to an existing one, or polling raw build status is not exposed via MCP. Use the Cloud UI for those (Datapack → Actions → Add Knowledge).
|
|
62
62
|
|
|
63
|
-
**Adding a file** is a registered MCP tool: call `knowledgebase_upload_document` directly (accepted extensions PDF/TXT/MD/JSON/CSV/XML/HTML, up to 5 MB Free / 50 MB Standard / 60 MB Pro+ per file) to get a presigned URL, then POST the bytes to it yourself; Meko registers and indexes the file once it lands, so no separate index-management call is needed. Confirm with the user first, because every datapack member can read the knowledge base. The Cloud UI's **Add Knowledge** flow (10 files per batch) remains the human-facing path for the same upload.
|
|
63
|
+
**Adding a file** is a registered MCP tool: if you can send the file's bytes in an HTTPS POST to an external URL yourself (a sandboxed session may have the file but no outbound network), call `knowledgebase_upload_document` directly (accepted extensions PDF/TXT/MD/JSON/CSV/XML/HTML, up to 5 MB Free / 50 MB Standard / 60 MB Pro+ per file) to get a presigned URL, then POST the bytes to it yourself; Meko registers and indexes the file once it lands, so no separate index-management call is needed. Confirm with the user first, because every datapack member can read the knowledge base. The Cloud UI's **Add Knowledge** flow (10 files per batch) remains the human-facing path for the same upload.
|
|
64
64
|
|
|
65
65
|
To **query** a built index, use `knowledgebase_search` — it returns both uploaded documents and memories the user promoted from the Learnings tab.
|
|
66
66
|
|
|
@@ -85,7 +85,7 @@ It works **poorly** for:
|
|
|
85
85
|
conversation_id="<session conversation_id>",
|
|
86
86
|
text="Customer Complaints dataset has fields: Complaint ID (int PK), Date Submitted (date), Product (text, e.g. Mortgage/Credit Card), Sub-product (text), Issue (text), Company Response (text), State (text, 2-letter code), ZIP Code (text)")
|
|
87
87
|
```
|
|
88
|
-
2. **Upload the file itself to the knowledge base** with `knowledgebase_upload_document
|
|
88
|
+
2. **Upload the file itself to the knowledge base** with `knowledgebase_upload_document`, if you can POST its bytes yourself — `.csv`, `.json` and the other accepted types go in as they are — and query it with `knowledgebase_search`. (The Cloud UI's **Add Knowledge** flow does the same for a person.)
|
|
89
89
|
|
|
90
90
|
Never ingest CSV row-by-row into memory — each row becomes a fragmented fact with lost context.
|
|
91
91
|
|
|
@@ -85,7 +85,7 @@ Agents on Cloud Meko have two distinct read surfaces. Pick the right one for the
|
|
|
85
85
|
- **Personal memories** — written by `memory_add`. The `agent_id` records the writer but does not restrict reads; memories are scoped **per-user**, so any of that user's agents can read them via MCP, and no other user can.
|
|
86
86
|
- **Team-shared Shared Knowledge** — arrives two ways:
|
|
87
87
|
1. An agent calls `memory_promote` for exact, user-confirmed memory UUIDs, or the user promotes them from the Cloud UI's Learnings tab. Promotion moves the memories into shared knowledge, strips `user_id`, preserves originating `agent_id` as provenance, and evicts the private mem0 records.
|
|
88
|
-
2.
|
|
88
|
+
2. A file is uploaded — by an agent with `knowledgebase_upload_document`, or by the user via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/CSV/XML/HTML up to 5MB (Free) / 50MB (Standard) / 60MB (Pro+) each.
|
|
89
89
|
|
|
90
90
|
Both show up in `knowledgebase_search`, tagged `metadata_filters.source: "memory"` vs other values so the agent can distinguish provenance in responses.
|
|
91
91
|
|
|
@@ -102,7 +102,7 @@ Call `context_search`. One call returns your personal memories (every agent, no
|
|
|
102
102
|
There is no MCP-side "just put it in a database table" option — raw SQL access isn't part of the MCP surface. Workarounds:
|
|
103
103
|
|
|
104
104
|
1. **Write a single narrative summary** as a memory: `"The Customer Complaints dataset has fields: Complaint ID (int), Date Submitted (date), Product (text), Sub-product (text), Issue (text)..."` — one call, not row-by-row.
|
|
105
|
-
2. **
|
|
105
|
+
2. **Upload the file** with `knowledgebase_upload_document` if you have it and can POST its bytes to an external URL yourself, or suggest the user upload it via the Cloud UI's Add Knowledge flow, if it's a document (PDF/TXT/MD/JSON/CSV/XML/HTML are supported).
|
|
106
106
|
3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context.
|
|
107
107
|
|
|
108
108
|
## Memory Storage: automatic, not proactive
|
|
@@ -108,14 +108,14 @@ Some things the Meko platform can do are not wired into the MCP tool surface tod
|
|
|
108
108
|
|
|
109
109
|
| Capability | Where it lives | How to reach it |
|
|
110
110
|
|---|---|---|
|
|
111
|
-
| Create / list / delete **agents** within a datapack |
|
|
112
|
-
| Add / list / delete **knowledge-base sources** on a datapack |
|
|
113
|
-
| Langfuse project-key generation |
|
|
111
|
+
| Create / list / delete **agents** within a datapack | Meko API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (`POST/GET/DELETE /agents/:agent` for targeted deletes), or the Meko control-plane UI |
|
|
112
|
+
| Add / list / delete **knowledge-base sources** on a datapack | Meko API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases`, plus `upload-url`, `upload-complete`, `create`, `status` subroutes. Also available in the Meko UI. |
|
|
113
|
+
| Langfuse project-key generation | Meko API server | REST: `POST /datapacks/:datapack_id/langfuse/project-keys` |
|
|
114
114
|
| Account / billing / tier management | Meko UI only | Not available via MCP or public REST |
|
|
115
115
|
|
|
116
116
|
The MCP-exposed `datapack_create` / `datapack_search` / `datapack_list` / `datapack_describe` / `datapack_update` / `datapack_delete` tools above are a deliberate subset — the common CRUD that an agent reasonably needs mid-conversation. Anything involving agent or KB lifecycle is control-plane territory.
|
|
117
117
|
|
|
118
|
-
For a file already on disk or generated mid-conversation, requesting a URL with `knowledgebase_upload_document` and POSTing to it gets it into the KB without leaving MCP for a human's help. The UI upload path (Datapack → Actions → **Add Knowledge**, PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) remains the way for a human to add files directly. `knowledgebase_search` queries the resulting index either way.
|
|
118
|
+
For a file already on disk or generated mid-conversation, and when you can send the file's bytes in an HTTPS POST to an external URL yourself (a sandboxed session may have the file but no outbound network), requesting a URL with `knowledgebase_upload_document` and POSTing to it gets it into the KB without leaving MCP for a human's help. The UI upload path (Datapack → Actions → **Add Knowledge**, PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) remains the way for a human to add files directly. `knowledgebase_search` queries the resulting index either way.
|
|
119
119
|
|
|
120
120
|
## Common Parameter Patterns
|
|
121
121
|
|
|
@@ -129,6 +129,8 @@ From `cloud.mekodata.ai`:
|
|
|
129
129
|
|
|
130
130
|
If a *human* asks you "how do I add a document to my knowledge base?",
|
|
131
131
|
point them at this flow. If *you* (the agent) have the file's bytes —
|
|
132
|
-
already on disk, or generated mid-conversation —
|
|
132
|
+
already on disk, or generated mid-conversation — and can send them in an
|
|
133
|
+
HTTPS POST to an external URL yourself, call
|
|
133
134
|
`knowledgebase_upload_document` directly instead of describing the UI
|
|
134
|
-
flow to yourself.
|
|
135
|
+
flow to yourself. A sandboxed session may have the file but no outbound
|
|
136
|
+
network; point the user at the UI then.
|
|
@@ -17,7 +17,7 @@ description: >-
|
|
|
17
17
|
license: MIT
|
|
18
18
|
metadata:
|
|
19
19
|
author: Meko
|
|
20
|
-
version: "2.
|
|
20
|
+
version: "2.12.0"
|
|
21
21
|
tags: mcp, yugabytedb, tools, datapack, memory, conversation, rag, meko, desktop
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -146,7 +146,8 @@ Your job is not to decide fact-by-fact what to `memory_add`. It's to **post ever
|
|
|
146
146
|
| User asks "what do we (as a team) know about X?" or about uploaded documents | `knowledgebase_search` (returns uploaded docs + promoted memories). |
|
|
147
147
|
| User asks to share specific private memories with the team | Follow the `memory_promote` confirmation workflow below. Never promote based on a fuzzy search result or implied consent. |
|
|
148
148
|
| User provides structured/tabular data (CSV, data dictionary) | If it's an actual file the user wants in the team's knowledge base, `knowledgebase_upload_document` accepts `.csv` directly (confirm first; see below). If it's pasted/described data with no file behind it, still don't `memory_add` it row-by-row — ask the user for it as a file, or point them at the UI's Add Knowledge upload. |
|
|
149
|
-
| User wants
|
|
149
|
+
| User wants a file kept in Meko but didn't say how | KB (`knowledgebase_upload_document`) if its content should be searchable later — docs, manuals, policies, notes people will ask about. Artifact (`artifact_put`) to keep it exactly as-is and fetch it back whole — a generated report, a result CSV. If it is not clear whether the user needs semantic search or whole-file retrieval, ask. |
|
|
150
|
+
| User wants to add documents to the team's knowledge base | Uploading adds the file to the datapack's shared knowledge base, which every member can read, so ask first: name the file and the datapack, say the team will see it, and upload only after the user says yes. If you have the file's bytes — already on disk, or generated mid-conversation — and a shell or code tool, check that you can reach S3 first: run `curl -sS -o /dev/null -m 10 -w '%{http_code}' https://s3.amazonaws.com`; in Windows PowerShell, run `curl.exe` with `NUL` in place of `/dev/null`. A 2xx or 3xx status means yes (S3's root normally answers 307). `000`, a connection, DNS or proxy error, or any other status, such as a proxy's 403 or 407, means no. A pass shows outbound HTTPS to S3 works, not that the presigned bucket host does, so if the POST still fails, report it and stop. If it passes, call `knowledgebase_upload_document`. Claude Desktop usually has no shell; with no shell or code tool, or a failed check, don't call it, since an unused URL holds storage quota for up to 15 minutes. Otherwise point the user at the Cloud UI flow — Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch). KB *lifecycle* (index/source management) is still UI-only. |
|
|
150
151
|
|
|
151
152
|
## Conversation capture — mechanics
|
|
152
153
|
|
|
@@ -269,7 +270,7 @@ The Cloud UI's Learnings tab remains an alternative user-driven path.
|
|
|
269
270
|
3. **agent_id is multi-agent**: For Claude Desktop, use `agent_id="claude_desktop"` for normal writes and `agent_id="meko_agent"` for cross-project facts. Writes are attributed to `(datapack_id, user_id, agent_id)`. Personal memory reads and `conversation_list` span all of this user's agents; `conversation_get` remains agent-owned. `knowledgebase_search` ignores `agent_id` entirely. See `tools-agent-id-conventions.md`.
|
|
270
271
|
4. **Personal memory vs. team-shared knowledge**: Un-promoted memories are scoped per-user — readable across all of that user's agents, but no other user can see them. With explicit confirmation, `memory_promote` moves exact memories into Shared Knowledge; the Cloud UI's Learnings tab is an alternative. Promoted content is visible to every datapack member. `knowledgebase_search` is the MCP read path for both Shared Knowledge and uploaded documents.
|
|
271
272
|
5. **conversation_id IS the Langfuse trace ID**: every MCP tool call inside a conversation becomes a span under that trace. Observable in the Meko UI's Observe hub. See `tools-memory-vs-conversation.md`.
|
|
272
|
-
6. **Adding a file to a knowledge base**: the file becomes visible to every datapack member, so confirm with the user first. Call `knowledgebase_upload_document` only if you have the file's bytes and can
|
|
273
|
+
6. **Adding a file to a knowledge base**: the file becomes visible to every datapack member, so confirm with the user first. Call `knowledgebase_upload_document` only if you have the file's bytes and can send them in an HTTPS POST to an external URL yourself (a local shell, or a code tool with internet access); Claude Desktop usually can't, so point the user at the UI instead. Use the KB when the content should be searchable later, `artifact_put` to keep a file whole. A human uploads via Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each) instead. KB *lifecycle* (creating/renaming/deleting an index, adding a source manually) has no MCP tool and is still UI-only. See `tools-rag-workflow.md`.
|
|
273
274
|
7. **Manual conversation capture**: Claude Desktop does not have automatic capture hooks. Create and save conversations explicitly when sessions are valuable.
|
|
274
275
|
8. **Memory latencies are not cheap**: observed on prod 2026-05-07 — `memory_add` 12-21s/call (calls OpenAI), `memory_search` 2-6s/call. Budget accordingly. On the Free tier, `conversation_add_message` and `context_search` are each capped at 1,000 lifetime calls, and `memory_search` and `knowledgebase_search` at 1,000. Per-turn capture draws down the `conversation_add_message` cap, so on Free skip trivial turns. When a call returns `free_tier_limit_reached`, report it and stop calling that tool; it can arrive as HTTP 403 but isn't an authentication problem.
|
|
275
276
|
9. **Known limitations**: see `tools-known-limitations.md` before attempting write operations on tools that appear in the catalog but aren't available on Cloud.
|
|
@@ -295,7 +295,7 @@ Returns `{"document_id", "chunks_deleted", "s3_deleted"}` — if `s3_deleted` is
|
|
|
295
295
|
|
|
296
296
|
### knowledgebase_upload_document
|
|
297
297
|
|
|
298
|
-
**When to use:** Get a file's bytes into the datapack's KB for later `knowledgebase_search` retrieval — a file already on disk, or one generated mid-conversation. This tool never touches the file's bytes itself; it only requests a presigned S3 URL. Meko registers the file once it lands, so there's no separate confirm call. **The caller POSTs the file to the returned `url` directly** — multipart/form-data, every key in `fields` as a form field (in order), then the file's bytes last as a field named `"file"`.
|
|
298
|
+
**When to use:** Get a file's bytes into the datapack's KB for later `knowledgebase_search` retrieval — a file already on disk, or one generated mid-conversation. Use it when the content should be searchable by meaning; to keep a file exactly as-is and fetch it back whole, use `artifact_put`. Before calling it, check that you can reach S3 first: run `curl -sS -o /dev/null -m 10 -w '%{http_code}' https://s3.amazonaws.com`; in Windows PowerShell, run `curl.exe` with `NUL` in place of `/dev/null`. A 2xx or 3xx status means yes (S3's root normally answers 307). `000`, a connection, DNS or proxy error, or any other status, such as a proxy's 403 or 407, means no. A pass shows outbound HTTPS to S3 works, not that the presigned bucket host does, so if the POST still fails, report it and stop. With no shell or code tool, or a failed check, don't call it — point the user at the UI. This tool never touches the file's bytes itself; it only requests a presigned S3 URL. Meko registers the file once it lands, so there's no separate confirm call. **The caller POSTs the file to the returned `url` directly** — multipart/form-data, every key in `fields` as a form field (in order), then the file's bytes last as a field named `"file"`.
|
|
299
299
|
|
|
300
300
|
**Confirm first.** The file goes into the datapack's shared knowledge base, which every member can read. Before calling the tool, tell the user which file and datapack, say the team will see it, and wait for a yes.
|
|
301
301
|
|
|
@@ -464,7 +464,7 @@ Poll until `state` is `completed` or `failed` (or the pre-registration terminals
|
|
|
464
464
|
|
|
465
465
|
### artifact_put
|
|
466
466
|
|
|
467
|
-
**When to use:** An agent has generated a file (report, CSV, PDF, code output, image) and wants to persist it in Meko for later retrieval or cross-agent sharing. Files < 1 MB are stored inline in the DB; files ≥ 1 MB go to the datapack's S3 bucket. Idempotent — uploading the same bytes twice returns the same `content_hash`.
|
|
467
|
+
**When to use:** An agent has generated a file (report, CSV, PDF, code output, image) and wants to persist it in Meko for later retrieval or cross-agent sharing. To make its content searchable by meaning instead, use `knowledgebase_upload_document`. Files < 1 MB are stored inline in the DB; files ≥ 1 MB go to the datapack's S3 bucket. Idempotent — uploading the same bytes twice returns the same `content_hash`.
|
|
468
468
|
|
|
469
469
|
```
|
|
470
470
|
artifact_put(
|
|
@@ -596,4 +596,4 @@ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/li
|
|
|
596
596
|
- REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
|
|
597
597
|
- Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
|
|
598
598
|
|
|
599
|
-
Uploading a *file* into an existing KB is not part of that lifecycle restriction — use `knowledgebase_upload_document` (see above) rather than the UI for anything driven from MCP. Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
|
|
599
|
+
Uploading a *file* into an existing KB is not part of that lifecycle restriction — use `knowledgebase_upload_document` (see above) rather than the UI for anything driven from MCP, when you can POST the file's bytes yourself. Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
|
|
@@ -18,7 +18,7 @@ The one exception is a single uploaded **file**: `knowledgebase_delete_document`
|
|
|
18
18
|
|
|
19
19
|
Manually creating a vector index, adding a source to an existing one, or polling raw build status is not exposed via MCP. Use the Cloud UI for those (Datapack → Actions → Add Knowledge).
|
|
20
20
|
|
|
21
|
-
**Adding a file** is a registered MCP tool: call `knowledgebase_upload_document` directly (accepted extensions PDF/TXT/MD/JSON/CSV/XML/HTML, up to 5 MB Free / 50 MB Standard / 60 MB Pro+ per file) to get a presigned URL, then POST the bytes to it yourself; Meko registers and indexes the file once it lands, so no separate index-management call is needed. Confirm with the user first, because every datapack member can read the knowledge base. The Cloud UI's **Add Knowledge** flow (10 files per batch) remains the human-facing path for the same upload.
|
|
21
|
+
**Adding a file** is a registered MCP tool: if you can send the file's bytes in an HTTPS POST to an external URL yourself (a local shell, or a code tool with internet access), call `knowledgebase_upload_document` directly (accepted extensions PDF/TXT/MD/JSON/CSV/XML/HTML, up to 5 MB Free / 50 MB Standard / 60 MB Pro+ per file) to get a presigned URL, then POST the bytes to it yourself; Meko registers and indexes the file once it lands, so no separate index-management call is needed. Confirm with the user first, because every datapack member can read the knowledge base. The Cloud UI's **Add Knowledge** flow (10 files per batch) remains the human-facing path for the same upload.
|
|
22
22
|
|
|
23
23
|
To **query** a built index, use `knowledgebase_search` — it returns both uploaded documents and memories the user promoted from the Learnings tab.
|
|
24
24
|
|
|
@@ -43,7 +43,7 @@ It works **poorly** for:
|
|
|
43
43
|
conversation_id="<session conversation_id>",
|
|
44
44
|
text="Customer Complaints dataset has fields: Complaint ID (int PK), Date Submitted (date), Product (text, e.g. Mortgage/Credit Card), Sub-product (text), Issue (text), Company Response (text), State (text, 2-letter code), ZIP Code (text)")
|
|
45
45
|
```
|
|
46
|
-
2. **Upload the file itself to the knowledge base** with `knowledgebase_upload_document
|
|
46
|
+
2. **Upload the file itself to the knowledge base** with `knowledgebase_upload_document`, if you can POST its bytes yourself — `.csv`, `.json` and the other accepted types go in as they are — and query it with `knowledgebase_search`. (The Cloud UI's **Add Knowledge** flow does the same for a person.)
|
|
47
47
|
|
|
48
48
|
Never ingest CSV row-by-row into memory — each row becomes a fragmented fact with lost context.
|
|
49
49
|
|
|
@@ -85,7 +85,7 @@ One `memory_search` already spans this user's memories across all agents; no per
|
|
|
85
85
|
- **Personal memories** — written by `memory_add`. The `agent_id` records the writer but does not restrict reads; memories are scoped per-user, so any of that user's agents can read them and no other user can.
|
|
86
86
|
- **Team-shared Shared Knowledge** — arrives two ways:
|
|
87
87
|
1. An agent calls `memory_promote` for exact, user-confirmed memory UUIDs, or the user promotes them from the Cloud UI's Learnings tab. Promotion moves the memories into shared knowledge, strips `user_id`, preserves originating `agent_id` as provenance, and evicts the private mem0 records.
|
|
88
|
-
2.
|
|
88
|
+
2. A file is uploaded — by an agent with `knowledgebase_upload_document`, or by the user via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/CSV/XML/HTML up to 5MB (Free) / 50MB (Standard) / 60MB (Pro+) each.
|
|
89
89
|
|
|
90
90
|
Both show up in `knowledgebase_search`, tagged `metadata_filters.source: "memory"` vs other values so the agent can distinguish provenance in responses.
|
|
91
91
|
|
|
@@ -114,7 +114,7 @@ When you answer, be explicit about scope so the user knows why something is or i
|
|
|
114
114
|
There is no MCP-side "just put it in a database table" option — raw SQL access isn't part of the MCP surface. Workarounds:
|
|
115
115
|
|
|
116
116
|
1. **Write a single narrative summary** as a memory: `"The Customer Complaints dataset has fields: Complaint ID (int), Date Submitted (date), Product (text), Sub-product (text), Issue (text)..."` — one call, not row-by-row.
|
|
117
|
-
2. **
|
|
117
|
+
2. **Upload the file** with `knowledgebase_upload_document` if you have it and can POST its bytes to an external URL yourself, or suggest the user upload it via the Cloud UI's Add Knowledge flow, if it's a document (PDF/TXT/MD/JSON/CSV/XML/HTML are supported).
|
|
118
118
|
3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context.
|
|
119
119
|
|
|
120
120
|
## Memory Storage: capture the turn, don't proactively memory_add
|
|
@@ -108,14 +108,14 @@ Some things the Meko platform can do are not wired into the MCP tool surface tod
|
|
|
108
108
|
|
|
109
109
|
| Capability | Where it lives | How to reach it |
|
|
110
110
|
|---|---|---|
|
|
111
|
-
| Create / list / delete **agents** within a datapack |
|
|
112
|
-
| Add / list / delete **knowledge-base sources** on a datapack |
|
|
113
|
-
| Langfuse project-key generation |
|
|
111
|
+
| Create / list / delete **agents** within a datapack | Meko API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (`POST/GET/DELETE /agents/:agent` for targeted deletes), or the Meko control-plane UI |
|
|
112
|
+
| Add / list / delete **knowledge-base sources** on a datapack | Meko API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases`, plus `upload-url`, `upload-complete`, `create`, `status` subroutes. Also available in the Meko UI. |
|
|
113
|
+
| Langfuse project-key generation | Meko API server | REST: `POST /datapacks/:datapack_id/langfuse/project-keys` |
|
|
114
114
|
| Account / billing / tier management | Meko UI only | Not available via MCP or public REST |
|
|
115
115
|
|
|
116
116
|
The MCP-exposed `datapack_create` / `datapack_search` / `datapack_list` / `datapack_describe` / `datapack_update` / `datapack_delete` tools above are a deliberate subset — the common CRUD that an agent reasonably needs mid-conversation. Anything involving agent or KB lifecycle is control-plane territory.
|
|
117
117
|
|
|
118
|
-
For a file already on disk or generated mid-conversation, requesting a URL with `knowledgebase_upload_document` and POSTing to it gets it into the KB without leaving MCP for a human's help. The UI upload path (Datapack → Actions → **Add Knowledge**, PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) remains the way for a human to add files directly. `knowledgebase_search` queries the resulting index either way.
|
|
118
|
+
For a file already on disk or generated mid-conversation, and when you can send the file's bytes in an HTTPS POST to an external URL yourself (a local shell, or a code tool with internet access), requesting a URL with `knowledgebase_upload_document` and POSTing to it gets it into the KB without leaving MCP for a human's help. The UI upload path (Datapack → Actions → **Add Knowledge**, PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) remains the way for a human to add files directly. `knowledgebase_search` queries the resulting index either way.
|
|
119
119
|
|
|
120
120
|
## Common Parameter Patterns
|
|
121
121
|
|
|
@@ -129,6 +129,7 @@ From `cloud.mekodata.ai`:
|
|
|
129
129
|
|
|
130
130
|
If a *human* asks you "how do I add a document to my knowledge base?",
|
|
131
131
|
point them at this flow. If *you* (the agent) have the file's bytes —
|
|
132
|
-
already on disk, or generated mid-conversation —
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
already on disk, or generated mid-conversation — and can send them in an
|
|
133
|
+
HTTPS POST to an external URL yourself (a local shell, or a code tool with
|
|
134
|
+
internet access), call `knowledgebase_upload_document` directly instead
|
|
135
|
+
of describing the UI flow to yourself.
|
|
@@ -10,6 +10,7 @@ import { askChoice, askMultiChoice, askText, askSecret, askYesNo, close as close
|
|
|
10
10
|
import { banner, error, dim, info, success, warn } from '../lib/logger.mjs';
|
|
11
11
|
import { BrowserLoginError, consoleUrlFor, loginAndCreateApiKey } from '../lib/browser-login.mjs';
|
|
12
12
|
import {
|
|
13
|
+
isLocalUrl,
|
|
13
14
|
isPackagedInstall,
|
|
14
15
|
MEKO_PRODUCTION_CONSOLE_URL,
|
|
15
16
|
selfInvocation,
|
|
@@ -86,6 +87,9 @@ function readVersion() {
|
|
|
86
87
|
return pkg.version;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
// The docker-compose dev stack that --local points at. It takes no API key.
|
|
91
|
+
const LOCAL_DEV_MCP_URL = 'http://localhost:8000/mcp';
|
|
92
|
+
|
|
89
93
|
const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex', 'kiro', 'opencode'];
|
|
90
94
|
|
|
91
95
|
function printHelp() {
|
|
@@ -139,11 +143,13 @@ Options:
|
|
|
139
143
|
untrusted IDE workspaces and non-managed CLI agents fall
|
|
140
144
|
back to agent-driven persistence.
|
|
141
145
|
--url <url> MCP server URL (from cloud.mekodata.ai > Datapacks > Connect)
|
|
142
|
-
--api-key <key> Use an existing
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
--api-key <key> Use an existing Meko API key (Cloud, or Meko Local's
|
|
147
|
+
client token) instead of signing in through the
|
|
148
|
+
browser. Also read from $MEKO_API_KEY for any URL
|
|
149
|
+
(ignored with --local). Required for Cloud when no
|
|
150
|
+
terminal is attached (CI, scripts).
|
|
145
151
|
--no-browser Print the sign-in URL instead of opening a browser
|
|
146
|
-
--local Use local Meko at http://localhost:8000/mcp
|
|
152
|
+
--local Use local Meko at http://localhost:8000/mcp (no API key)
|
|
147
153
|
--scope <scope> Config scope: user or project (default: user)
|
|
148
154
|
codex always installs at user scope (no project-level
|
|
149
155
|
config); --scope=project degrades with a warning.
|
|
@@ -225,10 +231,6 @@ Migrate existing conversations and memories into Meko:
|
|
|
225
231
|
console.log(text);
|
|
226
232
|
}
|
|
227
233
|
|
|
228
|
-
function isCloudUrl(url) {
|
|
229
|
-
return url && !url.includes('localhost') && !url.includes('127.0.0.1');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
234
|
/**
|
|
233
235
|
* Sanitize a raw API key from any source (CLI flag, env var, askSecret prompt).
|
|
234
236
|
*
|
|
@@ -479,7 +481,7 @@ async function main() {
|
|
|
479
481
|
}
|
|
480
482
|
let url = flags.url ?? process.env.MEKO_MCP_URL ?? null;
|
|
481
483
|
let apiKey = normalizeApiKey(flags['api-key'] ?? process.env.MEKO_API_KEY);
|
|
482
|
-
if (flags.local) { url =
|
|
484
|
+
if (flags.local) { url = LOCAL_DEV_MCP_URL; apiKey = null; }
|
|
483
485
|
|
|
484
486
|
let parentRate;
|
|
485
487
|
try { parentRate = parseRate(flags.rate); }
|
|
@@ -558,11 +560,17 @@ async function main() {
|
|
|
558
560
|
// prompt. Someone answered that prompt, so sign-in runs even when stdin
|
|
559
561
|
// is not a TTY (e.g. piped answers in the smoke harness).
|
|
560
562
|
let choseBrowserSignIn = false;
|
|
563
|
+
// Set for --local, the interactive "Local Meko" choice, and a --yes run
|
|
564
|
+
// that reuses an existing LOCAL_DEV_MCP_URL entry: the docker-compose dev
|
|
565
|
+
// stack takes no key, so $MEKO_API_KEY is not read for it. An explicit
|
|
566
|
+
// --url, local or not, still reads it.
|
|
567
|
+
let keylessLocal = false;
|
|
561
568
|
|
|
562
569
|
// --local shortcut
|
|
563
570
|
if (flags.local) {
|
|
564
|
-
url =
|
|
571
|
+
url = LOCAL_DEV_MCP_URL;
|
|
565
572
|
apiKey = null;
|
|
573
|
+
keylessLocal = true;
|
|
566
574
|
}
|
|
567
575
|
|
|
568
576
|
// Client picker — runs for any interactive invocation (including
|
|
@@ -628,6 +636,11 @@ async function main() {
|
|
|
628
636
|
process.exit(1);
|
|
629
637
|
}
|
|
630
638
|
url = suggestedUrl.url;
|
|
639
|
+
// Reusing the dev stack an earlier --local install registered: keep it
|
|
640
|
+
// keyless, as --local would.
|
|
641
|
+
if (suggestedUrl.source === 'existing' && url === LOCAL_DEV_MCP_URL) {
|
|
642
|
+
keylessLocal = true;
|
|
643
|
+
}
|
|
631
644
|
}
|
|
632
645
|
}
|
|
633
646
|
|
|
@@ -689,8 +702,9 @@ async function main() {
|
|
|
689
702
|
}
|
|
690
703
|
}
|
|
691
704
|
} else {
|
|
692
|
-
url =
|
|
705
|
+
url = LOCAL_DEV_MCP_URL;
|
|
693
706
|
apiKey = null;
|
|
707
|
+
keylessLocal = true;
|
|
694
708
|
}
|
|
695
709
|
|
|
696
710
|
// Step 4 — skills
|
|
@@ -724,22 +738,32 @@ async function main() {
|
|
|
724
738
|
process.exit(1);
|
|
725
739
|
}
|
|
726
740
|
|
|
727
|
-
//
|
|
728
|
-
//
|
|
729
|
-
//
|
|
730
|
-
//
|
|
731
|
-
//
|
|
732
|
-
//
|
|
733
|
-
//
|
|
734
|
-
|
|
735
|
-
// at the browser, and a 5-minute callback wait would stall it. The one
|
|
736
|
-
// exception is an explicit "Sign in with browser" answer at the prompt.
|
|
737
|
-
if (isCloudUrl(url) && !apiKey) {
|
|
741
|
+
// API key resolution order: --api-key (already in `apiKey`) →
|
|
742
|
+
// $MEKO_API_KEY → browser sign-in (Cloud only).
|
|
743
|
+
//
|
|
744
|
+
// $MEKO_API_KEY applies to every URL, local ones included: Meko Local
|
|
745
|
+
// (the `meko` server, MCP on 127.0.0.1:7778) requires its client token,
|
|
746
|
+
// and AgentK passes that token only through the environment so it stays
|
|
747
|
+
// out of `ps`. Only the keyless dev stack (see `keylessLocal`) skips it.
|
|
748
|
+
if (!apiKey && !keylessLocal) {
|
|
738
749
|
apiKey = normalizeApiKey(process.env.MEKO_API_KEY);
|
|
739
|
-
let signInFailed = false;
|
|
740
750
|
if (apiKey) {
|
|
741
751
|
dim('Using API key from MEKO_API_KEY environment variable.');
|
|
742
|
-
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Validation — Cloud URL requires an API key. Browser sign-in creates one
|
|
756
|
+
// through the server's POST /api-keys. Sign-in also covers the cloud
|
|
757
|
+
// one-liner from the UI, which only shows --url and --client. It is
|
|
758
|
+
// skipped when the full interactive flow already took a pasted key (an
|
|
759
|
+
// empty paste is an error, not a silent switch to the browser), and
|
|
760
|
+
// whenever stdin is not a terminal, with or without --yes: a script or CI
|
|
761
|
+
// step may have nobody at the browser, and a 5-minute callback wait would
|
|
762
|
+
// stall it. The one exception is an explicit "Sign in with browser" answer
|
|
763
|
+
// at the prompt. A local URL with no key installs without one.
|
|
764
|
+
if (!isLocalUrl(url) && !apiKey) {
|
|
765
|
+
let signInFailed = false;
|
|
766
|
+
if (!promptedForApiKey && (process.stdin.isTTY || choseBrowserSignIn)) {
|
|
743
767
|
apiKey = await signInWithBrowser({
|
|
744
768
|
url,
|
|
745
769
|
noBrowser: flags['no-browser'],
|
package/lib/clients/codex.mjs
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
import {
|
|
39
39
|
getInstallerVersion,
|
|
40
40
|
installStableTree,
|
|
41
|
+
isLocalUrl,
|
|
41
42
|
isPackagedInstall,
|
|
42
43
|
isDanglingSymlink,
|
|
43
44
|
markerIsStale,
|
|
@@ -909,30 +910,6 @@ function buildCliRegisterCommand(name, url, bearerEnv) {
|
|
|
909
910
|
return cmd;
|
|
910
911
|
}
|
|
911
912
|
|
|
912
|
-
/**
|
|
913
|
-
* True for localhost / loopback MCP URLs (no cloud WAF in front). Parses the
|
|
914
|
-
* URL and compares the HOSTNAME exactly — a substring test would wrongly
|
|
915
|
-
* classify `https://localhost.example.com` (a real remote host) as local and
|
|
916
|
-
* skip the WAF User-Agent header. Unparseable input is treated as non-local
|
|
917
|
-
* (cloud), i.e. we err toward setting the header.
|
|
918
|
-
*/
|
|
919
|
-
function isLocalUrl(url) {
|
|
920
|
-
let host;
|
|
921
|
-
try {
|
|
922
|
-
host = new URL(String(url ?? "")).hostname;
|
|
923
|
-
} catch {
|
|
924
|
-
return false;
|
|
925
|
-
}
|
|
926
|
-
// `new URL` strips the brackets from IPv6 literals, so `[::1]` → `::1`.
|
|
927
|
-
host = host.replace(/^\[|\]$/g, "").toLowerCase();
|
|
928
|
-
return (
|
|
929
|
-
host === "localhost" ||
|
|
930
|
-
host === "::1" ||
|
|
931
|
-
// Entire 127.0.0.0/8 block is loopback, not just 127.0.0.1.
|
|
932
|
-
/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host)
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
|
-
|
|
936
913
|
const HTTP_HEADER_USER_AGENT_KEY = "User-Agent";
|
|
937
914
|
|
|
938
915
|
// Matches one `KEY = "VALUE"` (or single-quoted) pair. KEY may be
|
package/lib/clients/common.mjs
CHANGED
|
@@ -114,6 +114,31 @@ export function run(cmd) {
|
|
|
114
114
|
return execSync(cmd, { encoding: "utf8", stdio: "pipe" }).trim();
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* True for localhost / loopback MCP URLs (no cloud WAF in front, no browser
|
|
119
|
+
* sign-in). Parses the URL and compares the HOSTNAME exactly — a substring
|
|
120
|
+
* test would wrongly classify `https://localhost.example.com` (a real remote
|
|
121
|
+
* host) as local and `http://[::1]/mcp` as cloud. Unparseable input is
|
|
122
|
+
* treated as non-local (cloud): Codex errs toward setting the WAF User-Agent
|
|
123
|
+
* header, and the installer toward requiring an API key.
|
|
124
|
+
*/
|
|
125
|
+
export function isLocalUrl(url) {
|
|
126
|
+
let host;
|
|
127
|
+
try {
|
|
128
|
+
host = new URL(String(url ?? "")).hostname;
|
|
129
|
+
} catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
// `new URL` strips the brackets from IPv6 literals, so `[::1]` → `::1`.
|
|
133
|
+
host = host.replace(/^\[|\]$/g, "").toLowerCase();
|
|
134
|
+
return (
|
|
135
|
+
host === "localhost" ||
|
|
136
|
+
host === "::1" ||
|
|
137
|
+
// Entire 127.0.0.0/8 block is loopback, not just 127.0.0.1.
|
|
138
|
+
/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
117
142
|
/**
|
|
118
143
|
* @param {string|null|undefined} apiKey
|
|
119
144
|
* @returns {string}
|
package/lib/migrate.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import * as progress from "./migrate/progress.mjs";
|
|
|
20
20
|
import { datapackKeyFromUrl } from "./migrate/id.mjs";
|
|
21
21
|
import { resolveDestinationDatapack } from "./migrate/datapack.mjs";
|
|
22
22
|
import { McpClient } from "./migrate/mcp-client.mjs";
|
|
23
|
-
import { selfInvocation } from "./clients/common.mjs";
|
|
23
|
+
import { isLocalUrl, selfInvocation } from "./clients/common.mjs";
|
|
24
24
|
import { askYesNo } from "./prompt.mjs";
|
|
25
25
|
|
|
26
26
|
function home() {
|
|
@@ -764,7 +764,3 @@ export async function stopMigration() {
|
|
|
764
764
|
message: `Force-killed pid=${holder.pid} (run-id=${holder.runId}).`,
|
|
765
765
|
};
|
|
766
766
|
}
|
|
767
|
-
|
|
768
|
-
function isLocalUrl(url) {
|
|
769
|
-
return /localhost|127\.0\.0\.1/.test(url ?? "");
|
|
770
|
-
}
|