@foundation0/api 1.1.2 → 1.1.3
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/agents.ts +7 -6
- package/git.ts +2 -2
- package/mcp/AGENTS.md +130 -0
- package/mcp/server.test.ts +464 -250
- package/mcp/server.ts +2449 -1673
- package/package.json +2 -2
- package/projects.ts +582 -79
package/agents.ts
CHANGED
|
@@ -39,7 +39,7 @@ interface ActiveConfigInput {
|
|
|
39
39
|
required: boolean
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const CLI_NAME = '
|
|
42
|
+
const CLI_NAME = 'f0'
|
|
43
43
|
const AGENT_INITIAL_VERSION = 'v0.0.1'
|
|
44
44
|
const DEFAULT_SKILL_NAME = 'coding-standards'
|
|
45
45
|
const VERSION_RE = 'v?\\d+(?:\\.\\d+){2,}'
|
|
@@ -58,7 +58,7 @@ export function usage(): string {
|
|
|
58
58
|
`Use --latest to resolve /file-name to the latest version.\n` +
|
|
59
59
|
`The active file created is [file].active.<ext>.\n` +
|
|
60
60
|
`Use "run" to start codex with developer_instructions from system/prompt.ts.\n` +
|
|
61
|
-
`Set EXAMPLE_CODEX_BIN to pin a specific codex binary.\n`
|
|
61
|
+
`Set F0_CODEX_BIN (or EXAMPLE_CODEX_BIN) to pin a specific codex binary.\n`
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function resolveAgentsRoot(processRoot: string = process.cwd()): string {
|
|
@@ -460,9 +460,9 @@ export function setActiveLink(sourceFile: string, activeFile: string): 'symlink'
|
|
|
460
460
|
|
|
461
461
|
fs.mkdirSync(path.dirname(activeFile), { recursive: true })
|
|
462
462
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
463
|
+
// Remove the active pointer first. Using rmSync directly (instead of existsSync)
|
|
464
|
+
// ensures we also clear broken symlinks (existsSync returns false for them).
|
|
465
|
+
fs.rmSync(activeFile, { force: true })
|
|
466
466
|
|
|
467
467
|
const linkTarget = path.relative(path.dirname(activeFile), sourceFile)
|
|
468
468
|
|
|
@@ -643,7 +643,7 @@ type SpawnCodexResult = {
|
|
|
643
643
|
type SpawnCodexFn = (args: string[]) => SpawnCodexResult
|
|
644
644
|
|
|
645
645
|
function getCodexCommand(): string {
|
|
646
|
-
const override = process.env.EXAMPLE_CODEX_BIN?.trim()
|
|
646
|
+
const override = process.env.F0_CODEX_BIN?.trim() ?? process.env.EXAMPLE_CODEX_BIN?.trim()
|
|
647
647
|
if (override) {
|
|
648
648
|
return override
|
|
649
649
|
}
|
|
@@ -666,6 +666,7 @@ const defaultSpawnCodex: SpawnCodexFn = (args) => {
|
|
|
666
666
|
const err = primary.error as NodeJS.ErrnoException
|
|
667
667
|
if (
|
|
668
668
|
process.platform === 'win32'
|
|
669
|
+
&& !process.env.F0_CODEX_BIN
|
|
669
670
|
&& !process.env.EXAMPLE_CODEX_BIN
|
|
670
671
|
&& primaryCommand === 'codex.cmd'
|
|
671
672
|
&& err.code === 'ENOENT'
|
package/git.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type {
|
|
|
5
5
|
GitServiceApi,
|
|
6
6
|
GitServiceApiExecutionResult,
|
|
7
7
|
GitServiceApiMethod,
|
|
8
|
-
} from '
|
|
8
|
+
} from '@foundation0/git'
|
|
9
9
|
|
|
10
10
|
export {
|
|
11
11
|
attachGitLabelManagementApi,
|
|
@@ -17,4 +17,4 @@ export {
|
|
|
17
17
|
extractDependencyIssueNumbers,
|
|
18
18
|
resolveProjectRepoIdentity,
|
|
19
19
|
syncIssueDependencies,
|
|
20
|
-
} from '
|
|
20
|
+
} from '@foundation0/git'
|
package/mcp/AGENTS.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
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.
|