Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
34b6133
feat: add mcptools mcp catalog (V1)
cloudbridgeuy Sep 19, 2026
dea38fd
test: add shell catalog tests for mcp tool catalog
cloudbridgeuy Sep 19, 2026
2c1e372
feat: add find-tools CLI
cloudbridgeuy Sep 21, 2026
9492f5f
feat: register find_tools as MCP tool (V2)
cloudbridgeuy Sep 21, 2026
dbaece5
Add ToolKind with per-tool annotations on tools/list
cloudbridgeuy Sep 21, 2026
7cc550d
Classify full 62-tool table per kind oracle
cloudbridgeuy Sep 21, 2026
658f85b
test: lock 62-tool name set per kind as closed-world gate
cloudbridgeuy Sep 21, 2026
018d632
add jsonschema 0.56 as workspace dep; reference as dev-dep in mcptools
cloudbridgeuy Sep 21, 2026
b6e0ce8
replace hand-rolled validator with jsonschema draft202012 in contract…
cloudbridgeuy Sep 21, 2026
3fe3a2c
V2: Authentic samples and nullable outputs
cloudbridgeuy Sep 21, 2026
014f31d
V3: change TicketOutput.comments to Vec<CommentOutput>; map via trans…
cloudbridgeuy Sep 21, 2026
ad3ae7f
implement V4: unreached function in conformance_tests and enrich all …
cloudbridgeuy Sep 21, 2026
0f9e442
core: add jev module with Provider, GatewayConfig, Secret, build_requ…
cloudbridgeuy Sep 21, 2026
876cdfc
shell: add jev module with classify and timeout
cloudbridgeuy Sep 21, 2026
7ec53fc
update contract sample for new backend field in FoundTools
cloudbridgeuy Sep 21, 2026
5b71b81
V2: add FallbackReason and wire through find_tools_with and attach_sc…
cloudbridgeuy Sep 21, 2026
6932bff
V2: document Jev env vars in CLAUDE.md, add find_tools section with b…
cloudbridgeuy Sep 21, 2026
ab273a2
fix(find_tools): cover fallback path in contract sample
cloudbridgeuy Sep 21, 2026
da05c84
feat(mcp): add discovery list mode that lists only find_tools
cloudbridgeuy Sep 21, 2026
20454e4
Add mcptools_core::ts_decl TypeScript declaration emitter
cloudbridgeuy Sep 21, 2026
329cca3
Add mcp declarations command printing tool TypeScript declarations
cloudbridgeuy Sep 21, 2026
08d7817
Emit anyOf unions and prefixItems tuples in TS declarations, sweep wh…
cloudbridgeuy Sep 21, 2026
a59e3c4
docs: add mcptools mcp declarations to MCP Server commands
cloudbridgeuy Sep 21, 2026
9fcefbf
Rank required golden rows on local ranker via tokenizer synonyms
cloudbridgeuy Sep 21, 2026
8f9f702
V2: record live Jev runs and document agent loop
cloudbridgeuy Sep 21, 2026
c9b0d2d
feat(mcp): return TypeScript declarations and usage from find_tools
cloudbridgeuy Sep 22, 2026
6a4e63a
docs: point the find_tools agent loop at declarations
cloudbridgeuy Sep 22, 2026
72c2d03
Gate find_tools tools/list entry at 1300 chars
cloudbridgeuy Sep 22, 2026
78d2b17
Add QuickJS sandbox runner with log capture and typed JS errors
cloudbridgeuy Sep 22, 2026
f554ff8
Bound sandbox execution with interrupt deadline, outer timeout, and o…
cloudbridgeuy Sep 22, 2026
e2db07e
Cover sandbox bounds with deadline, output-cap, memory, and ticker tests
cloudbridgeuy Sep 22, 2026
a0b5fdd
Add execute limit flags and Global::sandbox_limits
cloudbridgeuy Sep 22, 2026
c28f3e2
Add tool_result structuredContent unwrap to core sandbox
cloudbridgeuy Sep 22, 2026
97c6c46
Expose MCP tool globals in the QuickJS sandbox
cloudbridgeuy Sep 22, 2026
8f8c915
core: return Run from sandbox, add execute_output
cloudbridgeuy Sep 22, 2026
7713f18
sandbox: run returns Run, keep logs on every error path
cloudbridgeuy Sep 22, 2026
215f67e
mcp: register execute tool and add its handler
cloudbridgeuy Sep 22, 2026
8e8486f
docs: describe execute tool and its requirement scenarios
cloudbridgeuy Sep 22, 2026
27b66d0
core: derive Deserialize for execute output types
cloudbridgeuy Sep 22, 2026
264bcb9
tests: account for execute in counts, oracles, and samples
cloudbridgeuy Sep 22, 2026
9973018
tests: expect execute in contract_pilot name list
cloudbridgeuy Sep 22, 2026
0319a29
execute: name the flag in ReferenceError messages for gated tools
cloudbridgeuy Sep 23, 2026
69a2f55
tests: add stdio MCP harness with spawn, request, tools_call
cloudbridgeuy Sep 23, 2026
c1191f3
tests: e2e jira execute chain against wiremock stub
cloudbridgeuy Sep 23, 2026
84143d4
tests: add two-section PDF fixture
cloudbridgeuy Sep 23, 2026
d50345d
tests: cover section-scoped pdf calls end to end
cloudbridgeuy Sep 23, 2026
98c62ad
tests: gate jira chain writes behind allowWrites
cloudbridgeuy Sep 23, 2026
a129e2a
refactor: extract shared browser opener from images
cloudbridgeuy Sep 24, 2026
b0a5308
feat: add linear chart command for issue dependency diagrams
cloudbridgeuy Sep 24, 2026
ffc34dc
mcp: declare serve flags on mcp command and thread them through handlers
cloudbridgeuy Sep 24, 2026
6c5c927
find_tools: select usage text by code-mode flag
cloudbridgeuy Sep 24, 2026
866591d
mcp: gate tools/list by serve flags with code-mode precedence
cloudbridgeuy Sep 24, 2026
0f7be07
docs: sync mcp serve flag docs with code-mode and boolish env values
cloudbridgeuy Sep 24, 2026
038b7b6
core: add pure projection engine for dotted field paths
cloudbridgeuy Sep 24, 2026
bbe1898
mcp: wire pdf_read fields projection
cloudbridgeuy Sep 24, 2026
b54cc21
tests: e2e pdf_read field projection over mcp stdio
cloudbridgeuy Sep 24, 2026
bac9075
mcp: wire fields projection for jira_search and linear_issue_list
cloudbridgeuy Sep 24, 2026
c1c5ac1
mcp: wire fields projection for md_fetch and bitbucket_pr_read
cloudbridgeuy Sep 24, 2026
b665700
docs: record optional fields projection behavior for five MCP tools
cloudbridgeuy Sep 24, 2026
90a6563
test: rename e2e fields projection tests to match filter
cloudbridgeuy Sep 24, 2026
85c602a
test: pin TypeScript declarations for md_fetch and bitbucket_pr_read
cloudbridgeuy Sep 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude/context/linear.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ Selector rules:
- `--query` matches a title substring. `--updated-after` needs RFC3339 and is rejected before any request when malformed.
- Issue update `--state` names resolve from the issue identifier team (`GUZ-22` → `GUZ`). `--team` overrides. UUID issue ids still need `--team` or a state UUID.

### Chart

```bash
# Render an HTML Mermaid chart of issues, sub-issues, and blockers, then open it
mcptools linear chart GUZ-185 GUZ-186 GUZ-188
mcptools linear chart GUZ-185 --out /tmp/linear-chart.html
mcptools linear chart GUZ-185 --no-open
```

`chart` walks the transitive closure of children and `blocked_by` blockers (cap 300 issues, warning on the cap), drops canceled issues, and classifies the rest as complete, in progress, frontier (ready to start), or fog (prerequisite incomplete). Output defaults to `<temp dir>/mcptools-linear-chart.html`. Empty issue ids reject before any request.

### Discovery

```bash
Expand Down
106 changes: 106 additions & 0 deletions .claude/context/mcp-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ mcptools mcp sse --port 3000 --host 127.0.0.1

For web-based clients using Server-Sent Events over HTTP.

mcptools mcp catalog # Print the compact tool catalog (domain, name, summary)
mcptools mcp declarations [NAME...] # Print TypeScript declarations for named tools (all tools without names)

## Claude Desktop Configuration

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
Expand Down Expand Up @@ -131,6 +134,109 @@ Or manually add to `~/Library/Application Support/Claude/claude_code_config.json
| `ui_annotations_resolve` | Mark annotation as resolved |
| `ui_annotations_clear` | Clear all annotations |

### Find tools

| Tool | Description |
|------|-------------|
| `find_tools` | Ranks registered tools for a task description. Returns `none` score, `tools` list with a TypeScript `declaration` per tool, `backend` ("local" or "jev"), optional `fallback` ("unreachable" | "http_status" | "invalid_response" | "invalid_config"), and `usage`. |

`find_tools` is advisory: it never dispatches a tool, and a Jev outage never blocks the caller.

**Jev environment variables**

| Variable | Default | Description |
|----------|---------|-------------|
| `JEV_PROVIDER` | unset | `opencode`, `openrouter`, `vercel` or `typesafe` to enable Jev classifier |
| `JEV_ENDPOINT` | provider preset | Override endpoint URL |
| `JEV_MODEL` | provider preset | Override model name |
| `JEV_API_KEY` | (none) | API key; falls back to the provider's conventional key var |
| `OPENCODE_API_KEY` | - | Conventional key var when `JEV_PROVIDER=opencode` |
| `OPENROUTER_API_KEY` | - | Conventional key var when `JEV_PROVIDER=openrouter` |
| `AI_GATEWAY_API_KEY` | - | Conventional key var when `JEV_PROVIDER=vercel` |
| `TYPESAFE_API_KEY` | - | Conventional key var when `JEV_PROVIDER=typesafe` |

### Execute

| Tool | Description |
|------|-------------|
| `execute` | Run JavaScript in a sandbox that binds the tools `find_tools` returns |

Inputs:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `code` | string | (required) | JavaScript to run; the final expression or top-level `return` value becomes `result` |
| `allowWrites` | boolean | `false` | Also bind tools of kind Write |
| `allowSpend` | boolean | `false` | Also bind tools of kind Spend |

Result shape, the `structuredContent` object:

| Field | Type | Description |
|-------|------|-------------|
| `logs` | string[] | Lines captured from `console.log` up to the failure point |
| `result` | any | Final expression or top-level return value; `null` when `error` is set |
| `error` | object \| null | `null` on success; otherwise `{message, name}` |

The envelope carries `isError: true` exactly when `error` is non-null. On
failure `result` is `null` and `logs` still holds the lines printed before the
failure.

Error names:

- `TimeoutError` — the run exceeded `--execute-timeout-secs`
- `OutputLimitError` — the logs and result exceeded `--execute-output-kb`
- JavaScript error names pass through unchanged (`TypeError`, `Error`, and so
on); memory exhaustion surfaces as `InternalError`

Flag gating is by tool kind only: read tools bind by default, `allowWrites`
adds write tools, `allowSpend` adds spend tools, and `execute` never binds as
a global inside its own sandbox. A missing gated tool rejects with a
`ReferenceError` whose message names the tool, its kind, and the flag to pass
(e.g. `jira_update is a write tool; pass allowWrites: true to execute`); any
other missing global keeps QuickJS's plain `<name> is not defined` message.

Limits come from the server flags `--execute-timeout-secs` (default 30),
`--execute-memory-mb` (default 64), and `--execute-output-kb` (default 256).

## Agent loop

1. Call `find_tools` with a task that names the system (e.g. "mark the Jira ticket done", not "mark it done").
2. Read the returned `declaration` on the tool(s) of interest.
3. Call the tool by name through `tools/call`.
4. For a same-domain follow-up (e.g. `jira_comment_list` then `jira_comment_update`), call the follow-up tool directly; do not call `find_tools` again.
5. `find_tools` is advisory: it never dispatches a tool, and Jev is consulted only inside `find_tools` itself, never in front of or around any other tool call.
6. In discovery mode the loop needs a host that can call a tool absent from `tools/list` — see the Known limitation in [Discovery mode](#discovery-mode) below; this section restates none of that text.

## Discovery mode

Enable with the `--discovery` flag or the `MCPTOOLS_DISCOVERY` environment
variable. Env values are case-insensitive booleans: `y`, `yes`, `t`, `true`,
`on`, `1` enable the mode; `n`, `no`, `f`, `false`, `off`, `0` keep it off;
any other value, including an empty one, exits with code 2 and the error
`value was not a boolean`. In this mode `tools/list` returns exactly one tool,
`find_tools`; `tools/call` still dispatches every real tool by name. Without
this mode, hosts load all 63 schemas and Jev saves no context.

Known limitation, planned and undesigned: hosts that declare only listed
tools to the model, such as Claude Code, cannot yet call a tool directly
when it is absent from `tools/list`. The returned declarations name the
tools/call arguments and results of every tool they carry. Code mode closes
this gap in practice: `tools/list` returns `execute` beside `find_tools`, and
tools bind inside `execute` as async globals, under the flag gating
documented in [Execute](#execute) above.

## Code mode

Enable with the `--code-mode` flag or the `MCPTOOLS_CODE_MODE` environment
variable, with the same accepted values as `MCPTOOLS_DISCOVERY`. In this mode
`tools/list` returns exactly two tools, in order: `find_tools`, then
`execute`. Code mode wins over Discovery mode when both are enabled.
`tools/call` still dispatches every real tool by name. The `find_tools`
response `usage` field, also for nested `find_tools` calls inside `execute`,
is `Call each declared function as an async global inside execute.`; other
modes keep `Each declaration is the call signature: the input interface is
the tools/call arguments object, the Promise type is the result.`

## Testing with curl

```bash
Expand Down
29 changes: 29 additions & 0 deletions .claude/context/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All CLI arguments can be provided via environment variables, useful for scriptin
| Variable | Description |
|----------|-------------|
| `MCPTOOLS_VERBOSE` | Enable verbose output (default: false) |
| `MCPTOOLS_DISCOVERY` | List only `find_tools` via `tools/list`. Accepts `y`, `yes`, `t`, `true`, `on`, `1` (on) and `n`, `no`, `f`, `false`, `off`, `0` (off), any case; other values exit 2 (default: false) |
| `MCPTOOLS_CODE_MODE` | List `find_tools,execute` via `tools/list`; wins over `MCPTOOLS_DISCOVERY`. Same accepted values, other values exit 2 (default: false) |

## Atlassian Variables

Expand Down Expand Up @@ -83,6 +85,33 @@ All CLI arguments can be provided via environment variables, useful for scriptin
| `OPENAI_API_KEY` | Key for `--api openai` |
| `OPENAI_BASE_URL` | Base URL for `--api openai` (default: `https://api.openai.com/v1`) |

## Jev Variables

| Variable | Description |
|----------|-------------|
| `JEV_PROVIDER` | `opencode`, `openrouter`, `vercel` or `typesafe` to enable Jev (unset selects local) |
| `JEV_ENDPOINT` | Override gateway endpoint (defaults from provider) |
| `JEV_MODEL` | Override model (defaults from provider) |
| `JEV_API_KEY` | API key (falls back to the provider's conventional variable) |
| `OPENCODE_API_KEY` | Key used by `opencode` preset |
| `OPENROUTER_API_KEY` | Key used by `openrouter` preset |
| `AI_GATEWAY_API_KEY` | Key used by `vercel` preset |
| `TYPESAFE_API_KEY` | Key used by `typesafe` preset |

On `jev-1.13-free` the full 61-tool catalog plus `none` returns in under 1.2 s per call. `none` separates in-scope from out-of-scope tasks except for one near-miss. The 0.05-floor selection rule matches the live probabilities for every query the spike ran. This covers the `opencode` preset only; other presets are unverified beyond gateway documentation.

Live run against the `opencode` preset, one row per query (`JEV_PROVIDER=opencode`, `-k 5`, timed per call):

| task | backend | fallback | none | tools | latency |
|------|---------|----------|------|-------|---------|
| `mark the ticket done` | `jev` | — | 0.01 | `jira_update`, `linear_issue_update` | 1.2 s |
| `table of contents of this pdf` | `jev` | — | 0.0 | `pdf_toc` | 1.4 s |
| `table of contents of this web page` | `jev` | — | 0.0 | `md_toc` | 1.2 s |
| `update the jira comment I just listed` | `jev` | — | 0.0 | `jira_comment_update` | 1.2 s |
| `jira_comment_update` | `jev` | — | 0.0 | `jira_comment_update` | 1.9 s |
| `pdf_toc` | `jev` | — | 0.0 | `pdf_toc` | 1.1 s |
| `book a flight to Paris` | `jev` | — | 1.0 | — | 1.1 s |

## Usage Examples

### Scripting
Expand Down
20 changes: 20 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ export ATLASSIAN_API_TOKEN="your-api-token"
| `ATLAS_FILE_MODEL` | `gpt-5.6-luna` | Model for file descriptions |
| `ATLAS_DIR_MODEL` | `gpt-5.6-luna` | Model for directory descriptions |

**Jev**

| Variable | Default | Description |
|----------|---------|-------------|
| `JEV_PROVIDER` | unset | `opencode`, `openrouter`, `vercel` or `typesafe` to enable Jev classifier |
| `JEV_ENDPOINT` | provider preset | Override endpoint URL |
| `JEV_MODEL` | provider preset | Override model name |
| `JEV_API_KEY` | (none) | API key; falls back to the provider's conventional key var |
| `OPENCODE_API_KEY` | - | Conventional key var when `JEV_PROVIDER=opencode` |
| `OPENROUTER_API_KEY` | - | Conventional key var when `JEV_PROVIDER=openrouter` |
| `AI_GATEWAY_API_KEY` | - | Conventional key var when `JEV_PROVIDER=vercel` |
| `TYPESAFE_API_KEY` | - | Conventional key var when `JEV_PROVIDER=typesafe` |

## Detailed Documentation

For detailed usage of each feature, see the context files:
Expand Down Expand Up @@ -142,6 +155,7 @@ mcptools linear issue list --assignee me --json
mcptools linear teams list
mcptools linear projects list --team GUZ
mcptools linear users list --query "Ada"
mcptools linear chart GUZ-185 GUZ-186 GUZ-188
```

### Bitbucket
Expand Down Expand Up @@ -192,9 +206,15 @@ mcptools md fetch https://docs.example.com --selector "main"

```bash
mcptools mcp stdio # For local agents (Claude Desktop)
mcptools mcp stdio --discovery # tools/list returns only find_tools (env: MCPTOOLS_DISCOVERY=true)
mcptools mcp stdio --code-mode # tools/list returns find_tools,execute (env: MCPTOOLS_CODE_MODE=true)
mcptools mcp sse # For web clients
mcptools mcp catalog # Print the compact tool catalog (domain, name, summary)
mcptools mcp declarations [NAME...] # Print TypeScript declarations for named tools (all tools without names)
```

Find `find_tools` with a task that names the system, read the declaration, call the tool by name, and call same-domain follow-ups directly without another `find_tools` call. See [.claude/context/mcp-server.md#agent-loop](.claude/context/mcp-server.md#agent-loop) for the full loop and the discovery-mode limitation.

## Setup Guides

- [Atlassian Setup](docs/ATLASSIAN_SETUP.md) - Detailed setup instructions
Expand Down
Loading
Loading