@foundation0/api 1.1.12 → 1.1.13
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 +128 -128
- package/agents.ts +918 -918
- package/git.ts +20 -20
- package/libs/curl.ts +770 -770
- package/mcp/cli.mjs +37 -37
- package/mcp/cli.ts +87 -87
- package/mcp/client.ts +565 -565
- package/mcp/index.ts +15 -15
- package/mcp/server.ts +2991 -2991
- package/net.ts +170 -170
- package/package.json +13 -9
- package/projects.ts +4250 -4340
- package/taskgraph-parser.ts +217 -217
- package/libs/curl.test.ts +0 -130
- package/mcp/AGENTS.md +0 -130
- package/mcp/client.test.ts +0 -142
- package/mcp/manual.md +0 -179
- package/mcp/server.test.ts +0 -967
package/mcp/AGENTS.md
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# MCP Endpoint Design (LLM-Friendly)
|
|
2
|
-
|
|
3
|
-
This folder contains the Foundation0 MCP server (`api/mcp/server.ts`) and CLI (`api/mcp/cli.ts`).
|
|
4
|
-
|
|
5
|
-
These notes exist because the most common “LLM friction” issues are predictable:
|
|
6
|
-
- tool name/prefix confusion (duplicate names, “tool not found”),
|
|
7
|
-
- payload-shape confusion (positional `args` vs object options, or proxy tools that require JSON strings),
|
|
8
|
-
- oversized responses (truncation → extra tool calls),
|
|
9
|
-
- weak errors (not actionable → retries and wasted calls).
|
|
10
|
-
|
|
11
|
-
Use this doc when adding or modifying MCP endpoints so models can succeed in **one call**.
|
|
12
|
-
|
|
13
|
-
## 1) Avoid Tool Prefix Double-Wrapping
|
|
14
|
-
|
|
15
|
-
If your agent uses `pi-mcp-adapter` (or any MCP proxy that already prefixes tools), do **not** also run the server with `--tools-prefix`.
|
|
16
|
-
|
|
17
|
-
Bad (creates confusing duplicates like `f0_f0_net_curl` and `f0_net_curl`):
|
|
18
|
-
- Agent tool prefixing: `toolPrefix: "server"` (adds `f0_...`)
|
|
19
|
-
- Server tool prefixing: `--tools-prefix f0` (adds `f0....`)
|
|
20
|
-
|
|
21
|
-
Good (single predictable name):
|
|
22
|
-
- Agent: `toolPrefix: "server"`
|
|
23
|
-
- Server: no `--tools-prefix`
|
|
24
|
-
|
|
25
|
-
## 2) Prefer Direct Tools for Hot Paths (Fewer Calls, Fewer Errors)
|
|
26
|
-
|
|
27
|
-
Proxy-based MCP gateways often require passing `args` as a **JSON string** (not an object), which LLMs frequently get wrong.
|
|
28
|
-
|
|
29
|
-
If a tool is used often (HTTP, search, file ops), expose it as a **direct tool** in the agent config:
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"mcp": {
|
|
34
|
-
"mcpServers": {
|
|
35
|
-
"f0": {
|
|
36
|
-
"directTools": ["net_curl", "batch"]
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Note: Direct tool names must be OpenAI-tool-name-safe (no dots). Use the underscore aliases (e.g., `net_curl`) when exposing direct tools.
|
|
44
|
-
|
|
45
|
-
Benefits:
|
|
46
|
-
- The model calls `f0_net_curl` directly (no gateway wrapper).
|
|
47
|
-
- The model passes a normal JSON object (no “args must be a JSON string” confusion).
|
|
48
|
-
- Tool discoverability improves (tool appears in the system prompt).
|
|
49
|
-
|
|
50
|
-
Guideline: keep direct tools to a focused set (5–20). Use proxy for large catalogs.
|
|
51
|
-
|
|
52
|
-
## 3) Always Support a “Structured Mode” (Don’t Force Curl-CLI Literacy)
|
|
53
|
-
|
|
54
|
-
LLMs naturally try:
|
|
55
|
-
```json
|
|
56
|
-
{ "url": "https://…", "method": "GET", "headers": { "accept": "application/json" } }
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
If your tool only accepts positional CLI-like args (e.g. `{ "args": ["-L", "…"] }`), the model will often:
|
|
60
|
-
- guess the wrong shape,
|
|
61
|
-
- call `describe`,
|
|
62
|
-
- retry,
|
|
63
|
-
- and burn multiple tool calls.
|
|
64
|
-
|
|
65
|
-
Best practice:
|
|
66
|
-
- support **both** shapes:
|
|
67
|
-
- Curl-style: `{ "args": ["-L", "https://…"] }`
|
|
68
|
-
- Structured: `{ "url": "https://…", "method": "GET", ... }`
|
|
69
|
-
|
|
70
|
-
For `net.curl` (alias `net_curl`), structured mode should accept the common fields:
|
|
71
|
-
- `url`/`urls`, `method`, `headers`, `body`/`data`/`json`, `followRedirects`, `includeHeaders`,
|
|
72
|
-
- `fail`, `silent`, `verbose`, `writeOut`,
|
|
73
|
-
- `timeoutMs`, `maxTimeSeconds`, `maxRedirects`,
|
|
74
|
-
- `output`/`remoteName`, `user`.
|
|
75
|
-
|
|
76
|
-
Also: keep field names intuitive (`url`, `method`, `headers`, `body`) even if internally you translate to an `args[]` array.
|
|
77
|
-
|
|
78
|
-
## 4) Write a Tight Schema + Examples (Make the First Call Succeed)
|
|
79
|
-
|
|
80
|
-
Tool schemas are often the only thing an LLM sees.
|
|
81
|
-
|
|
82
|
-
Do:
|
|
83
|
-
- Provide a schema that shows **both** modes (positional `args[]` + structured keys).
|
|
84
|
-
- Add short descriptions that include **an example payload**.
|
|
85
|
-
- Prefer `additionalProperties: true` to allow forwards-compatible additions.
|
|
86
|
-
|
|
87
|
-
Avoid:
|
|
88
|
-
- schemas that only describe `args` but not recommended “structured mode”.
|
|
89
|
-
- schema-required fields that don’t exist for the other mode.
|
|
90
|
-
|
|
91
|
-
## 5) Make Errors Actionable (Self-Correct in One Retry)
|
|
92
|
-
|
|
93
|
-
When rejecting input:
|
|
94
|
-
- Use clear “what you passed / what I expected” wording.
|
|
95
|
-
- Include a copy/paste example.
|
|
96
|
-
- Provide likely tool-name suggestions when tool lookup fails.
|
|
97
|
-
|
|
98
|
-
If you control the gateway layer:
|
|
99
|
-
- Treat argument-shape failures as `isError: true` so the LLM knows to correct (not continue).
|
|
100
|
-
|
|
101
|
-
## 6) Keep Outputs Small by Default (Prevent Truncation)
|
|
102
|
-
|
|
103
|
-
Large outputs cause:
|
|
104
|
-
- truncation (the model misses the answer),
|
|
105
|
-
- follow-up calls,
|
|
106
|
-
- and sometimes tool-call loops.
|
|
107
|
-
|
|
108
|
-
Do:
|
|
109
|
-
- omit base64-encoded blobs by default (make them opt-in),
|
|
110
|
-
- provide `-o/--output` style file outputs for large bodies,
|
|
111
|
-
- include lightweight metadata (status code, headers, elapsed time).
|
|
112
|
-
|
|
113
|
-
## 7) Add Tests that Simulate “LLM Mistakes”
|
|
114
|
-
|
|
115
|
-
Every new endpoint should include tests that cover:
|
|
116
|
-
- structured payload success (`{ url, method }`),
|
|
117
|
-
- curl-style args success (`{ args: [...] }`),
|
|
118
|
-
- invalid shape failure (missing URL),
|
|
119
|
-
- “tool not found” suggestion behavior (server-side).
|
|
120
|
-
|
|
121
|
-
Tests belong next to the server/tool code (Bun tests under `api/`).
|
|
122
|
-
|
|
123
|
-
## 8) Endpoint Implementation Checklist
|
|
124
|
-
|
|
125
|
-
When adding `root.namespace.tool`:
|
|
126
|
-
- Add it under an explicit namespace (`net.*`, `projects.*`, etc.), not the root.
|
|
127
|
-
- Add/adjust `TOOL_INPUT_SCHEMA_OVERRIDES[toolName]` with examples.
|
|
128
|
-
- Ensure tool access is correct (read vs write vs admin).
|
|
129
|
-
- Ensure agent configs include the root endpoint in `--allowed-root-endpoints` when needed.
|
|
130
|
-
- Consider `directTools` for high-frequency tools.
|
package/mcp/client.test.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
|
|
2
|
-
import fs from 'node:fs/promises'
|
|
3
|
-
import os from 'node:os'
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
import { ExampleMcpClient } from './client'
|
|
6
|
-
|
|
7
|
-
type RawToolResponse = {
|
|
8
|
-
isError?: boolean
|
|
9
|
-
content: Array<{ type: 'text'; text: string }>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const toRawToolResponse = (data: unknown, isError = false): RawToolResponse => ({
|
|
13
|
-
isError,
|
|
14
|
-
content: [
|
|
15
|
-
{
|
|
16
|
-
type: 'text',
|
|
17
|
-
text: JSON.stringify(data),
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
const toGitFileToolData = (content: string) => ({
|
|
23
|
-
ok: true,
|
|
24
|
-
status: 200,
|
|
25
|
-
body: {
|
|
26
|
-
path: 'README.md',
|
|
27
|
-
type: 'file',
|
|
28
|
-
encoding: 'base64',
|
|
29
|
-
size: Buffer.byteLength(content, 'utf8'),
|
|
30
|
-
content: Buffer.from(content, 'utf8').toString('base64'),
|
|
31
|
-
},
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
describe('ExampleMcpClient git file guard', () => {
|
|
35
|
-
let cacheDir: string
|
|
36
|
-
let client: ExampleMcpClient
|
|
37
|
-
let capturedRequests: unknown[]
|
|
38
|
-
|
|
39
|
-
beforeEach(async () => {
|
|
40
|
-
cacheDir = await fs.mkdtemp(path.join(os.tmpdir(), 'f0-mcp-client-test-'))
|
|
41
|
-
capturedRequests = []
|
|
42
|
-
client = new ExampleMcpClient({
|
|
43
|
-
maxInlineFileLines: 3,
|
|
44
|
-
fileCacheDir: cacheDir,
|
|
45
|
-
requestTimeoutMs: 1_000,
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
afterEach(async () => {
|
|
50
|
-
await fs.rm(cacheDir, { recursive: true, force: true })
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const stubRequests = (handler: (request: any) => RawToolResponse): void => {
|
|
54
|
-
const internalClient = (client as any).client
|
|
55
|
-
internalClient.request = async (request: any) => {
|
|
56
|
-
capturedRequests.push(request)
|
|
57
|
-
return handler(request)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
it('blocks large file responses unless allowLargeSize is set', async () => {
|
|
62
|
-
const content = ['line 1', 'line 2', 'line 3', 'line 4'].join('\n')
|
|
63
|
-
stubRequests(() => toRawToolResponse(toGitFileToolData(content)))
|
|
64
|
-
|
|
65
|
-
const response = await client.call('repo.contents.view', {
|
|
66
|
-
args: ['owner', 'repo', 'README.md'],
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
expect(response.isError).toBe(true)
|
|
70
|
-
expect((response.data as any).hint).toContain('allowLargeSize')
|
|
71
|
-
expect((response.data as any).stats.lines).toBe(4)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('allows large file responses when allowLargeSize=true and strips client-only options', async () => {
|
|
75
|
-
const content = ['line 1', 'line 2', 'line 3', 'line 4'].join('\n')
|
|
76
|
-
stubRequests(() => toRawToolResponse(toGitFileToolData(content)))
|
|
77
|
-
|
|
78
|
-
const response = await client.call('repo.contents.view', {
|
|
79
|
-
args: ['owner', 'repo', 'README.md'],
|
|
80
|
-
options: {
|
|
81
|
-
allowLargeSize: true,
|
|
82
|
-
},
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
expect(response.isError).toBe(false)
|
|
86
|
-
expect((response.data as any).body.path).toBe('README.md')
|
|
87
|
-
expect((capturedRequests[0] as any).params.arguments.options).toBeUndefined()
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('downloads once and serves line-by-line reads from local cache', async () => {
|
|
91
|
-
const content = ['line 1', 'line 2', 'line 3', 'line 4'].join('\n')
|
|
92
|
-
stubRequests(() => toRawToolResponse(toGitFileToolData(content)))
|
|
93
|
-
|
|
94
|
-
const first = await client.call('repo.contents.view', {
|
|
95
|
-
args: ['owner', 'repo', 'README.md'],
|
|
96
|
-
options: {
|
|
97
|
-
line: 2,
|
|
98
|
-
},
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
expect(first.isError).toBe(false)
|
|
102
|
-
expect((first.data as any).lines).toEqual([{ line: 2, text: 'line 2' }])
|
|
103
|
-
expect(capturedRequests.length).toBe(1)
|
|
104
|
-
|
|
105
|
-
const second = await client.call('repo.contents.view', {
|
|
106
|
-
args: ['owner', 'repo', 'README.md'],
|
|
107
|
-
options: {
|
|
108
|
-
line: 3,
|
|
109
|
-
},
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
expect(second.isError).toBe(false)
|
|
113
|
-
expect((second.data as any).lines).toEqual([{ line: 3, text: 'line 3' }])
|
|
114
|
-
expect(capturedRequests.length).toBe(1)
|
|
115
|
-
|
|
116
|
-
const cacheEntries = await fs.readdir(cacheDir)
|
|
117
|
-
expect(cacheEntries.some((entry) => entry.endsWith('.txt'))).toBe(true)
|
|
118
|
-
expect(cacheEntries.some((entry) => entry.endsWith('.json'))).toBe(true)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('keeps non-file tool calls unchanged', async () => {
|
|
122
|
-
stubRequests(() => toRawToolResponse({ ok: true, body: { result: 'pass-through' } }))
|
|
123
|
-
|
|
124
|
-
const response = await client.call('projects.listProjects')
|
|
125
|
-
|
|
126
|
-
expect(response.isError).toBe(false)
|
|
127
|
-
expect(response.data).toEqual({ ok: true, body: { result: 'pass-through' } })
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('keeps plain-text tool responses as data when JSON parsing fails', async () => {
|
|
131
|
-
stubRequests(() => ({
|
|
132
|
-
isError: false,
|
|
133
|
-
content: [{ type: 'text', text: 'not-json' }],
|
|
134
|
-
}))
|
|
135
|
-
|
|
136
|
-
const response = await client.call('projects.listProjects')
|
|
137
|
-
|
|
138
|
-
expect(response.isError).toBe(false)
|
|
139
|
-
expect(response.text).toBe('not-json')
|
|
140
|
-
expect(response.data).toBe('not-json')
|
|
141
|
-
})
|
|
142
|
-
})
|
package/mcp/manual.md
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
# Foundation0 MCP Tool-Calling Manual (for LLMs)
|
|
2
|
-
|
|
3
|
-
This is a **tool-calling guide** for the Foundation0 MCP server in `api/mcp/*`.
|
|
4
|
-
Assume the server is already configured in your MCP host and you can call its tools.
|
|
5
|
-
|
|
6
|
-
## 0) Golden rules
|
|
7
|
-
|
|
8
|
-
1. If you are unsure about a tool name, call `mcp.listTools` first and use the exact name it returns (prefixes vary).
|
|
9
|
-
2. Use `mcp.describeTool` before your first call to a tool to get the input schema + an example payload.
|
|
10
|
-
3. Prefer named keys when possible (e.g. `projectName`, `repoName`) rather than relying on positional `args`.
|
|
11
|
-
4. `repoName` selects the active Git workspace identity. Use `adl` or `F0/adl`, or omit it to use the server default.
|
|
12
|
-
5. Tool results are returned as a **JSON text envelope**: parse the text as JSON and check `ok`.
|
|
13
|
-
|
|
14
|
-
Note: If you're unsure what the server can see (cwd/workspaceRoot/available repoName values), call `mcp.workspace`.
|
|
15
|
-
|
|
16
|
-
## 1) Tool naming (prefixes + aliases)
|
|
17
|
-
|
|
18
|
-
Depending on how the server was started, tool names may be:
|
|
19
|
-
|
|
20
|
-
- unprefixed: `projects.listProjects`
|
|
21
|
-
- prefixed: `api.projects.listProjects`
|
|
22
|
-
|
|
23
|
-
The server usually exposes both when a prefix is set, but do not assume: **discover at runtime** via `mcp.listTools`.
|
|
24
|
-
|
|
25
|
-
Some tools also have OpenAI-safe underscore aliases (no dots). Example:
|
|
26
|
-
|
|
27
|
-
- `net.curl` may also be available as `net_curl`
|
|
28
|
-
|
|
29
|
-
## 2) The 4 discovery calls
|
|
30
|
-
|
|
31
|
-
### A) List all tools
|
|
32
|
-
|
|
33
|
-
Tool call:
|
|
34
|
-
|
|
35
|
-
```json
|
|
36
|
-
{ "name": "mcp.listTools", "arguments": {} }
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### B) Describe one tool (schema + example)
|
|
40
|
-
|
|
41
|
-
Tool call (prefixed or unprefixed names both work here):
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{ "name": "mcp.describeTool", "arguments": { "args": ["projects.listProjects"] } }
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### C) `mcp.search` for "search docs/spec" requests
|
|
48
|
-
|
|
49
|
-
Tool call:
|
|
50
|
-
|
|
51
|
-
```json
|
|
52
|
-
{
|
|
53
|
-
"name": "mcp.search",
|
|
54
|
-
"arguments": {
|
|
55
|
-
"section": "spec",
|
|
56
|
-
"pattern": "authentication",
|
|
57
|
-
"paths": ["."],
|
|
58
|
-
"repoName": "<repo-name>",
|
|
59
|
-
"ignoreCase": true,
|
|
60
|
-
"maxCount": 50
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Notes:
|
|
66
|
-
- If only one project exists in the workspace, `projectName` is optional and will be inferred.
|
|
67
|
-
- If multiple projects exist, pass `projectName` explicitly.
|
|
68
|
-
|
|
69
|
-
### D) `mcp.workspace` to debug repoName/workspaceRoot/cwd issues
|
|
70
|
-
|
|
71
|
-
Tool call:
|
|
72
|
-
|
|
73
|
-
```json
|
|
74
|
-
{ "name": "mcp.workspace", "arguments": {} }
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## 3) Payload shapes (important)
|
|
78
|
-
|
|
79
|
-
Most tools accept either:
|
|
80
|
-
|
|
81
|
-
```json
|
|
82
|
-
{ "args": ["<project-name>"], "options": { "repoName": "<repo-name>" } }
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
or named keys (recommended). The server merges top-level keys into `options`:
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{ "projectName": "<project-name>", "repoName": "<repo-name>" }
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Guideline: if a tool has a natural named parameter (`projectName`, `agentName`, `target`, `taskRef`), pass it explicitly.
|
|
92
|
-
|
|
93
|
-
## 4) Common calls (examples)
|
|
94
|
-
|
|
95
|
-
### A) List projects
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"name": "projects.listProjects",
|
|
100
|
-
"arguments": { "repoName": "<repo-name>" }
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### E) Search specs without `projectName` (single-project workspaces)
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"name": "projects.searchSpecs",
|
|
109
|
-
"arguments": {
|
|
110
|
-
"pattern": "TASK-003",
|
|
111
|
-
"paths": ["07_roadmap/phases.md"],
|
|
112
|
-
"repoName": "<repo-name>",
|
|
113
|
-
"source": "auto"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### B) List agents
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"name": "agents.listAgents",
|
|
123
|
-
"arguments": { "repoName": "<repo-name>" }
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### C) Set an active file (projects)
|
|
128
|
-
|
|
129
|
-
```json
|
|
130
|
-
{
|
|
131
|
-
"name": "projects.setActive",
|
|
132
|
-
"arguments": {
|
|
133
|
-
"args": ["<project-name>", "/implementation-plan.v0.0.1"],
|
|
134
|
-
"options": { "repoName": "<repo-name>", "latest": true }
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### D) Batch multiple calls
|
|
140
|
-
|
|
141
|
-
Call `batch` (or `<prefix>.batch`) to run multiple tool calls:
|
|
142
|
-
|
|
143
|
-
```json
|
|
144
|
-
{
|
|
145
|
-
"name": "batch",
|
|
146
|
-
"arguments": {
|
|
147
|
-
"calls": [
|
|
148
|
-
{ "tool": "projects.usage" },
|
|
149
|
-
{ "tool": "projects.listProjects", "options": { "repoName": "<repo-name>" } }
|
|
150
|
-
],
|
|
151
|
-
"continueOnError": true,
|
|
152
|
-
"maxConcurrency": 4
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## 5) Reading responses (envelopes + errors)
|
|
158
|
-
|
|
159
|
-
Tool results are returned as text containing JSON like:
|
|
160
|
-
|
|
161
|
-
- success: `{ "ok": true, "result": ... }`
|
|
162
|
-
- error: `{ "ok": false, "error": { "message": "...", "details": { ... } } }`
|
|
163
|
-
|
|
164
|
-
If you get:
|
|
165
|
-
|
|
166
|
-
- **Unknown tool**: use the `suggestions` from the error (when present), or call `mcp.listTools` again and retry.
|
|
167
|
-
- **Missing project name**: pass `projectName` (or set `args[0]`).
|
|
168
|
-
- **Project folder not found**: call `mcp.workspace` and verify `workspaceRoot` plus `availableRepoNames` (use `adl` or `F0/adl`).
|
|
169
|
-
- **`projects.listProjects()` returns `[]` unexpectedly**: call `mcp.workspace` to confirm the server's `cwd`, `workspaceRoot`, and whether `/projects` exists.
|
|
170
|
-
|
|
171
|
-
## 6) Tool availability (read/write/admin)
|
|
172
|
-
|
|
173
|
-
The server can be started in modes that hide tools:
|
|
174
|
-
|
|
175
|
-
- read-only mode removes write-capable tools
|
|
176
|
-
- admin-only tools are hidden unless the server is started in admin mode
|
|
177
|
-
- root namespaces can be whitelisted (so entire namespaces may be missing)
|
|
178
|
-
|
|
179
|
-
If a tool is not listed by `mcp.listTools`, you cannot call it in the current server configuration.
|