champollion-mcp-server 0.3.2 → 0.4.0
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/CHANGELOG.md +67 -0
- package/LICENSE +1 -1
- package/README.md +34 -3
- package/bin/server.js +9 -3
- package/instructions-rails.md +129 -0
- package/instructions.md +1 -1
- package/package.json +7 -3
- package/src/index.js +32 -2
- package/src/rails.js +821 -0
- package/src/tools/forge.js +6 -4
- package/src/tools/harness.js +13 -6
- package/src/tools/language-card.js +1 -1
- package/src/tools/languages.js +46 -24
- package/src/tools/training.js +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 (2026-10-18) — on rails
|
|
4
|
+
|
|
5
|
+
### Fixed — found by the release candidate's packaged walk (2026-10-18)
|
|
6
|
+
|
|
7
|
+
- **`model_in_use` on `project_status`**: once a model is served, its try page
|
|
8
|
+
and the `champollion connect` command that puts it into an app or website
|
|
9
|
+
travel with the improve rounds' steps. The journey goes on to round 1 after
|
|
10
|
+
serving, so it never "finishes", and an agent on the rails never heard of
|
|
11
|
+
connect. The rails instructions and the agents' MCP page say what to do
|
|
12
|
+
with it (tell the person once; they run connect when they want it).
|
|
13
|
+
|
|
14
|
+
- **The rails profile is the default.** `npx champollion-mcp-server` now
|
|
15
|
+
starts the six-tool rails profile (start a language project, read its
|
|
16
|
+
next step, run it, add data, try the model, explain). Every other tool is
|
|
17
|
+
in the full profile: `--profile full` or `CHAMPOLLION_MCP_PROFILE=full`.
|
|
18
|
+
A client configured for the old default adds `--profile full`.
|
|
19
|
+
- **The rails tools.** `start_project` (a project folder with a place for
|
|
20
|
+
everything; a private-use code like `qaa` needs `target_name`),
|
|
21
|
+
`project_status` (THE next step, read from the project's files; with
|
|
22
|
+
`wait_seconds` it waits up to 120 s for a running step), `run_next_step`,
|
|
23
|
+
`add_data`, `try_translation` and `explain` (the rails, privacy, quality,
|
|
24
|
+
the step modes, stepping off the rails). Steps run as the same
|
|
25
|
+
`champollion` and `nmt-forge` commands a person types. The instructions
|
|
26
|
+
(`instructions-rails.md`) stay under 7,500 characters.
|
|
27
|
+
- **The people decide.** `run_next_step` runs only the step `project_status`
|
|
28
|
+
just named (the step ids must match) and refuses a step only a person can
|
|
29
|
+
take, or one that is waiting. A step that asks the data's holders runs
|
|
30
|
+
only with their answers, checked against what the step asks and put
|
|
31
|
+
into the command's arguments, never a shell string; an install or training
|
|
32
|
+
step runs only with `confirmed: true`. A step that failed twice in a row
|
|
33
|
+
runs again only when the person says so (`confirmed: true`); the refusal
|
|
34
|
+
hands back its last output.
|
|
35
|
+
- **Only the rails' own commands run:** `champollion`, `nmt-forge`, and
|
|
36
|
+
`uv tool install … nmt-forge` (`--python`, `--reinstall`, `--upgrade`).
|
|
37
|
+
Pipes, `;`, redirects, `$` and backticks are refused; a `#` starting a word
|
|
38
|
+
is a comment, as in a shell. Every command is a bounded process (10
|
|
39
|
+
minutes; 15 for the forge install). If `uv` is missing, the step is refused
|
|
40
|
+
with where the person installs it — the server never downloads or runs an
|
|
41
|
+
installer. When the installed `nmt-forge` is older than the rails need,
|
|
42
|
+
the tools step says both versions and offers the `--upgrade` install, for
|
|
43
|
+
the person to confirm.
|
|
44
|
+
- **`add_data`** brings in spreadsheets (.xlsx, .ods, .csv), .tsv/.txt files,
|
|
45
|
+
Word .docx tables, Toolbox and LIFT (FieldWorks) dictionaries, ELAN .eaf
|
|
46
|
+
files and, only when the person asks, USFM scripture: paired verse by verse
|
|
47
|
+
with the other language's text (`usfm_source`), held back from training
|
|
48
|
+
until its holders say so. `into` is `parallel`, `test` or `lexicon` (a word
|
|
49
|
+
list: the rails measure what looking words up scores). It reports counts
|
|
50
|
+
and columns, never sentences.
|
|
51
|
+
- **`try_translation`** translates up to 10 of the person's sentences with
|
|
52
|
+
the model the project serves on this computer (loopback only). What a
|
|
53
|
+
model writes is never relayed when it learned from local-only sentences or
|
|
54
|
+
its training terms were never recorded: the sentences are not sent, and
|
|
55
|
+
the agent gets the model's own page for the person to open. When the server asks for an
|
|
56
|
+
access token, the person tries it on that page; a token is never handed to
|
|
57
|
+
an agent.
|
|
58
|
+
- Full profile: `run_benchmark` takes method `lexicon` (the dictionary floor;
|
|
59
|
+
`model` is the dictionary file and is required, `attest_local_transport`
|
|
60
|
+
does not apply). `forge_status` in `serving` names
|
|
61
|
+
`npx champollion connect <model dir> --app <the app folder>` and says a
|
|
62
|
+
model trained on local-only sentences needs `--holders-agreed-by`, a forge
|
|
63
|
+
flag no tool ever passes: it is the holders' own answer, never an agent's.
|
|
64
|
+
- Tests: a scripted person (no LLM) walks the rails profile from an empty
|
|
65
|
+
folder to an evaluated model, to a private-use language and to a real one
|
|
66
|
+
by name; the same walk records the site's demo and runs from the packages
|
|
67
|
+
as they would ship. A lockstep test holds the `champollion` dependency
|
|
68
|
+
floor to the CLI in this tree.
|
|
69
|
+
|
|
3
70
|
## 0.3.2 (2026-10-07)
|
|
4
71
|
|
|
5
72
|
Requires champollion 0.5.3. The `translate` tool's default model is the
|
package/LICENSE
CHANGED
|
@@ -130,4 +130,4 @@ software under these terms.
|
|
|
130
130
|
**Use** means anything you do with the software requiring one
|
|
131
131
|
of your licenses.
|
|
132
132
|
|
|
133
|
-
Required Notice: Copyright
|
|
133
|
+
Required Notice: Copyright Epistemic Toolworks™ (Game Day Suits Ltd.) — Champollion (https://champollion.dev)
|
package/README.md
CHANGED
|
@@ -2,15 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
MCP (Model Context Protocol) server for Champollion. Lets an AI agent take a person from "we want machine translation for our language" to a measured, deployable model — find the language and what exists for it, keep the community's data private, baseline existing models (including ones on your own machine), train with guardrails, prove the result, and translate — plus browse and run the public benchmark queue.
|
|
4
4
|
|
|
5
|
-
> **Champollion
|
|
5
|
+
> **Champollion — on rails, with guardrails.** Machine translation development and deployment on rails, built with low-resource and Indigenous language communities in mind. This server is the agent's door onto the rails: its default profile gives a small agent six tools that walk a project from an empty folder to a measured model on the person's own computer, telling the agent to ask the person every question only they can answer (the server cannot check that it did), and reporting counts and columns — never a sentence from a local-only file. The rails promise process, not quality. This server itself is PolyForm Noncommercial 1.0.0 (see [LICENSE](LICENSE)): source-available and free for noncommercial use; using it for a commercial purpose is not covered by this license. Who is covered, in plain words with examples: [Who may use this](https://champollion.dev/docs/getting-started/who-may-use-this).
|
|
6
6
|
|
|
7
7
|
## What it does
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
It has two profiles:
|
|
10
|
+
|
|
11
|
+
- **rails** (the default) — six tools that walk one language project end to
|
|
12
|
+
end on the person's own computer, with instructions a small agent can hold
|
|
13
|
+
([below](#the-rails-profile--the-default)).
|
|
14
|
+
- **full** — every tool listed under [Tools](#tools), for the whole network
|
|
15
|
+
(atlas, benchmarks, forge, publishing): `npx champollion-mcp-server --profile full`
|
|
16
|
+
(or `CHAMPOLLION_MCP_PROFILE=full`).
|
|
17
|
+
|
|
18
|
+
When connected to an agent (Claude Code, Cursor, …) with the full profile, the server exposes tools, resources, and prompts built around one flow: **"let's build a model for our language — how do we start?"** — discover what exists → protect your own data → baseline → build → prove → deploy. (Contributing compute to the public benchmark is the second flow.)
|
|
10
19
|
|
|
11
20
|
### Tools
|
|
12
21
|
|
|
13
|
-
Arguments: `name` is required, `name?` is optional. Every tool that takes ONE language also accepts it as `language` — `code` / `language` means either name works (pass one). The original names keep working.
|
|
22
|
+
These are the full profile's (`--profile full`). Arguments: `name` is required, `name?` is optional. Every tool that takes ONE language also accepts it as `language` — `code` / `language` means either name works (pass one). The original names keep working.
|
|
14
23
|
|
|
15
24
|
#### Discover — what exists for a language
|
|
16
25
|
|
|
@@ -105,6 +114,28 @@ npm test # run unit tests
|
|
|
105
114
|
npm start # start on stdio (for agent connection)
|
|
106
115
|
```
|
|
107
116
|
|
|
117
|
+
### The rails profile — the default
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx champollion-mcp-server # the rails profile
|
|
121
|
+
npx champollion-mcp-server --profile full # every tool (or CHAMPOLLION_MCP_PROFILE=full)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Six tools and short instructions (`instructions-rails.md`, under 7,500
|
|
125
|
+
characters) that walk one language project end to end on the person's own
|
|
126
|
+
computer: `start_project`, `project_status` (THE next step, read from the
|
|
127
|
+
project's files), `run_next_step`, `add_data` (spreadsheets, Word tables,
|
|
128
|
+
.csv/.tsv, Toolbox and LIFT dictionaries, ELAN files, and USFM scripture on
|
|
129
|
+
request — counts and columns reported, never sentences), `try_translation`
|
|
130
|
+
(the served model on a few of the person's sentences — a model that learned
|
|
131
|
+
from local-only sentences is never relayed to the agent; the person gets its
|
|
132
|
+
page instead) and `explain`. The
|
|
133
|
+
people decide: `run_next_step` refuses a step only a person can take, runs a
|
|
134
|
+
step that asks the data's holders only with their answers, an install or
|
|
135
|
+
training step only with `confirmed: true`, and only the command
|
|
136
|
+
`project_status` just named. Every command is a bounded `champollion` or
|
|
137
|
+
`nmt-forge` process.
|
|
138
|
+
|
|
108
139
|
## Connect to your agent
|
|
109
140
|
|
|
110
141
|
### Claude Code / Antigravity
|
package/bin/server.js
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* an AI agent's MCP client (Claude Code, Antigravity, Cursor, etc.)
|
|
7
7
|
* or run directly for testing:
|
|
8
8
|
*
|
|
9
|
-
* node bin/server.js
|
|
9
|
+
* node bin/server.js # the rails profile (the default)
|
|
10
|
+
* node bin/server.js --profile full # every tool
|
|
10
11
|
*
|
|
11
|
-
* The
|
|
12
|
+
* The rails profile walks one language project end to end with six tools.
|
|
13
|
+
* The full profile exposes read-only tools for discovering what exists for a
|
|
12
14
|
* language (cited cards, benchmarks, results, contests), plus action tools
|
|
13
15
|
* that run benchmarks, drive nmt-forge training and translate — every one
|
|
14
16
|
* that spends or publishes requires the user's explicit confirmation.
|
|
@@ -16,5 +18,9 @@
|
|
|
16
18
|
|
|
17
19
|
import { createServer } from '../src/index.js';
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
// --profile rails (the default): the six-tool rails profile (src/rails.js);
|
|
22
|
+
// --profile full: every tool.
|
|
23
|
+
const i = process.argv.indexOf('--profile');
|
|
24
|
+
const profile = i >= 0 ? process.argv[i + 1] : undefined;
|
|
25
|
+
const server = await createServer(profile ? { profile } : undefined);
|
|
20
26
|
await server.start();
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Champollion — machine translation on rails
|
|
2
|
+
|
|
3
|
+
You help people build a translation method for their language, on their own
|
|
4
|
+
computer. The rails name every step; you walk them, and the people decide.
|
|
5
|
+
|
|
6
|
+
## The loop
|
|
7
|
+
|
|
8
|
+
1. No project yet → `start_project` (folder; `from` = the language they will
|
|
9
|
+
put in, `to` = the language they want out; a private-use code like `qaa`
|
|
10
|
+
needs its name). Pass each language exactly as the person named it — never
|
|
11
|
+
a name or code they did not say; a language they know no code for is `qaa`
|
|
12
|
+
with their name. No name for it yet? Ask what they want to call it for
|
|
13
|
+
now — their choice, never yours. Ask the person what the translations are for and pass it
|
|
14
|
+
as `purpose`. The first call makes nothing: say its `ask_first` to the
|
|
15
|
+
person, then make the call it gives for their answer.
|
|
16
|
+
2. `project_status` → read `step.mode`, `step.say`, `step.why`. `step.call`
|
|
17
|
+
is the exact tool call that takes the step (`step.command` is what the
|
|
18
|
+
rails run — never a tool name); a `<…>` in it is a slot for the person's
|
|
19
|
+
answer or file, never to be sent as it is.
|
|
20
|
+
3. Do what the mode says:
|
|
21
|
+
- **auto** — `run_next_step` with the `step_id`.
|
|
22
|
+
- **confirm** — tell the person what it does (installs, training), ask
|
|
23
|
+
yes/no; only on yes, `run_next_step` with `confirmed: true`. On "not
|
|
24
|
+
now", `run_next_step` with `declined: true`: nothing runs, and it is not
|
|
25
|
+
asked again this session. (When "not-now" is one of a question's own
|
|
26
|
+
answers, pass it in `answers` instead: it is recorded.)
|
|
27
|
+
- **ask_user** — ask the person `step.question` in plain words; pass their
|
|
28
|
+
answers, by the keys in `step.answers`, to `run_next_step`. Never answer
|
|
29
|
+
for them, never guess, never fill an answer from a file.
|
|
30
|
+
- **wait** — something is running. Make `step.call` (`project_status`,
|
|
31
|
+
waiting up to 2 minutes) and repeat it while the step stays `wait`. Only
|
|
32
|
+
if the tools said it takes hours, tell the person when to ask you again.
|
|
33
|
+
- **use_tool** — YOU do it now, with `step.tool` (e.g. `add_data` for the
|
|
34
|
+
files the person named), as `step.say` says. Do not hand it back.
|
|
35
|
+
- **human_only** — a person does it: tell them what `step.say` says.
|
|
36
|
+
4. Back to 2. After any change you or the person made by hand, call
|
|
37
|
+
`project_status` again — the next step is always read from the files.
|
|
38
|
+
5. No step left (`step: null`) → the rails are done: tell the person what
|
|
39
|
+
`finished` says (where to try the model, what they could do next).
|
|
40
|
+
|
|
41
|
+
## Bringing in data
|
|
42
|
+
|
|
43
|
+
`add_data` takes each file the person names WHERE IT IS — any path; never ask
|
|
44
|
+
them to move or copy it (`inbox/` is only a place they may drop files). Call
|
|
45
|
+
it with just the path first: it reads the layout itself (a header row naming
|
|
46
|
+
the languages decides the columns) and asks only when it cannot tell — don't
|
|
47
|
+
ask the person about columns or headers before trying. Use `into: "test"` for
|
|
48
|
+
the sentences a fluent speaker checked — the test set no model ever learns
|
|
49
|
+
from. If it asks which column is which language,
|
|
50
|
+
ask the person; never decide from the content. A result with `also` names
|
|
51
|
+
more in the same file (a dictionary's example sentences as pairs) and the
|
|
52
|
+
exact `add_data` call that brings it in — make it unless the person's terms
|
|
53
|
+
for that file rule it out. Every file the person named goes in: if
|
|
54
|
+
`files_not_added` appears, bring each in (its refusal says how) or tell the
|
|
55
|
+
person which is left out and why. Spreadsheets, Word tables,
|
|
56
|
+
Toolbox and LIFT dictionaries and ELAN files all come in this way; a word
|
|
57
|
+
list goes in with `into: "lexicon"` (the rails measure what looking words up
|
|
58
|
+
scores). Scripture (USFM) comes in only if the person asks, with the other
|
|
59
|
+
language's text as `usfm_source`, and no model learns from it until its
|
|
60
|
+
holders say so.
|
|
61
|
+
|
|
62
|
+
## Privacy — you are an outside service
|
|
63
|
+
|
|
64
|
+
What you read goes to your model provider. Never open, print or summarize the
|
|
65
|
+
person's data files, test sentences or dictionaries — use `add_data`, which
|
|
66
|
+
reports counts and columns only. A file marked local-only stays on this
|
|
67
|
+
computer, and the tools refuse anything that would send it away.
|
|
68
|
+
|
|
69
|
+
## Trying the model
|
|
70
|
+
|
|
71
|
+
Once the model is served, `try_translation` translates a few of the person's
|
|
72
|
+
own sentences with it. A model that learned from local-only sentences can
|
|
73
|
+
write them back, so for such a model you get only the address of its own page
|
|
74
|
+
— send the person there, and do not ask them to paste its translations to you.
|
|
75
|
+
|
|
76
|
+
## Making it better
|
|
77
|
+
|
|
78
|
+
A served model is where rounds begin, not where the rails end. Each round: a
|
|
79
|
+
wishlist sheet says what would help most, the people write sentences they want
|
|
80
|
+
translated, the model drafts them onto a sheet,
|
|
81
|
+
the speaker marks each draft right or wrong and fixes the wrong ones, and the
|
|
82
|
+
model learns again. Forge judges each round on the dev sentences and keeps the
|
|
83
|
+
model in use unless the new one is measurably better. The sheets hold their
|
|
84
|
+
sentences: never open them; relay the counts the tools print.
|
|
85
|
+
|
|
86
|
+
Each round ends with a report step (`champollion improve report`). Tell the
|
|
87
|
+
people what it says: the progress first — each number with its unit and what
|
|
88
|
+
it was measured on — then its checks and its next steps, as things they can do.
|
|
89
|
+
Encourage them with what is real; never more than the numbers say.
|
|
90
|
+
|
|
91
|
+
`waiting_for_agreement` lists files whose speakers have not agreed yet — the
|
|
92
|
+
rails go on without them. Ask each one's question once a session, gently; only
|
|
93
|
+
when the person says everyone agreed, make its call with their yes.
|
|
94
|
+
|
|
95
|
+
## Honesty
|
|
96
|
+
|
|
97
|
+
Pass on every caveat and warning the tools print, word for word. When you tell
|
|
98
|
+
the person what has been done — trained, scored, served — say it from
|
|
99
|
+
`true_now` in `project_status`, and never more than it says. The rails
|
|
100
|
+
promise the person will KNOW how good a model is on their own test sentences —
|
|
101
|
+
not that it is good. A small model trained on a few thousand pairs is usually a
|
|
102
|
+
phrasebook for phrases like the ones it saw. A fluent speaker decides what is
|
|
103
|
+
fit to use. Never call a score good or bad yourself; say what the tool said.
|
|
104
|
+
Then say it in plain words: chrF++ is out of 100 (higher is closer to the
|
|
105
|
+
speaker's own sentences); a range such as 14–22 is how sure the tools are, not
|
|
106
|
+
two results; a model is "the first small model", not its folder name.
|
|
107
|
+
|
|
108
|
+
Once a model is served, `project_status` carries `model_in_use` beside the
|
|
109
|
+
improve rounds' steps: its try page, and `for_the_person` — the command that
|
|
110
|
+
puts it into their app or website (`champollion connect`), which they run when
|
|
111
|
+
they want it. Tell them both once; the rounds go on either way.
|
|
112
|
+
|
|
113
|
+
## Money and installs
|
|
114
|
+
|
|
115
|
+
Nothing installs, trains, spends or publishes without the person's yes (the
|
|
116
|
+
confirm mode). If a step needs `uv` and it is missing, tell the person to
|
|
117
|
+
install it from https://docs.astral.sh/uv/ — do not download installers.
|
|
118
|
+
|
|
119
|
+
## When something refuses
|
|
120
|
+
|
|
121
|
+
A refusal says what, why and the fix. Pass it on in plain words and follow
|
|
122
|
+
the fix, or call `project_status`. A step that failed twice is not run again
|
|
123
|
+
until the person decides: tell them what it said, then either they fix it
|
|
124
|
+
(a corrected command in a terminal is fine) or they say to try again
|
|
125
|
+
(`confirmed: true`). `explain` has short texts on the rails,
|
|
126
|
+
privacy, quality, the modes, and stepping off the rails.
|
|
127
|
+
|
|
128
|
+
If they want help from people: "Having trouble, or want us to help with the
|
|
129
|
+
project? Let's talk" — https://champollion.dev. They never need us to finish.
|
package/instructions.md
CHANGED
|
@@ -10,7 +10,7 @@ for it.
|
|
|
10
10
|
|
|
11
11
|
## The flow this server is built for
|
|
12
12
|
|
|
13
|
-
Someone says: "Let's build a Cree model for our school" or "an Atya phrasebook for the hospital — how do we start?" Walk them through six stages. Each stage has tools. The human-readable version of this flow, with the exact commands, is https://champollion.dev/docs/
|
|
13
|
+
Someone says: "Let's build a Cree model for our school" or "an Atya phrasebook for the hospital — how do we start?" Walk them through six stages. Each stage has tools. The human-readable version of this flow, with the exact commands, is https://champollion.dev/docs/agents/shell — share it with the user.
|
|
14
14
|
|
|
15
15
|
| Stage | What it answers | Tools |
|
|
16
16
|
|---|---|---|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "champollion-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MCP server for Champollion — takes an agent from \"we want MT for our language\" to a measured model: cited language cards, benchmarks, local and hosted baselines, guarded nmt-forge training, contests, and the public benchmark queue.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"bin",
|
|
12
12
|
"src",
|
|
13
13
|
"instructions.md",
|
|
14
|
+
"instructions-rails.md",
|
|
14
15
|
"README.md",
|
|
15
16
|
"CHANGELOG.md",
|
|
16
17
|
"LICENSE"
|
|
@@ -27,7 +28,10 @@
|
|
|
27
28
|
"machine-translation",
|
|
28
29
|
"benchmarking",
|
|
29
30
|
"low-resource-languages",
|
|
30
|
-
"language-cards"
|
|
31
|
+
"language-cards",
|
|
32
|
+
"indigenous-languages",
|
|
33
|
+
"nmt-training",
|
|
34
|
+
"agents"
|
|
31
35
|
],
|
|
32
36
|
"author": "Curtis Forbes",
|
|
33
37
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
@@ -39,7 +43,7 @@
|
|
|
39
43
|
},
|
|
40
44
|
"dependencies": {
|
|
41
45
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
42
|
-
"champollion": "^0.
|
|
46
|
+
"champollion": "^0.6.0",
|
|
43
47
|
"zod": "^3.25 || ^4.0"
|
|
44
48
|
},
|
|
45
49
|
"repository": {
|
package/src/index.js
CHANGED
|
@@ -58,6 +58,7 @@ import { selectCorpora, formatCorpora, MAX_LIMIT as CORPORA_MAX_LIMIT } from './
|
|
|
58
58
|
import { metricReliability, formatReliability, cardFamilyClaims } from './tools/reliability.js';
|
|
59
59
|
import { translateTexts, formatTranslateResult, translateResultIsError, TRANSLATE_METHODS } from './tools/translate.js';
|
|
60
60
|
import { trainingGuardrails, formatTrainingGuardrails } from './tools/training.js';
|
|
61
|
+
import { registerRailsTools } from './rails.js';
|
|
61
62
|
import {
|
|
62
63
|
forgeTool, forgeToolsIn, FORGE_SCORING_TIMEOUT_MS, lintNextHint, lintSeverityCounts,
|
|
63
64
|
compareSummary, compareNextHint, discoverCardCrossCheck, preflightNextHint,
|
|
@@ -81,18 +82,47 @@ async function loadInstructions(path) {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
/** The rails profile's server: registerRailsTools + instructions-rails.md. */
|
|
86
|
+
async function createRailsServer(here) {
|
|
87
|
+
const instructions = await loadInstructions(resolve(here, '..', 'instructions-rails.md'));
|
|
88
|
+
const { version } = JSON.parse(await readFile(resolve(here, '..', 'package.json'), 'utf-8'));
|
|
89
|
+
const server = new McpServer({ name: 'champollion-rails', version },
|
|
90
|
+
instructions ? { instructions } : undefined);
|
|
91
|
+
registerRailsTools(server);
|
|
92
|
+
return {
|
|
93
|
+
async connect(transport) { await server.connect(transport); },
|
|
94
|
+
async start() {
|
|
95
|
+
await server.connect(new StdioServerTransport());
|
|
96
|
+
process.stderr.write('Champollion MCP server (rails profile) running on stdio\n');
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
84
101
|
/**
|
|
85
|
-
* Create and configure the MCP server
|
|
102
|
+
* Create and configure the MCP server.
|
|
103
|
+
*
|
|
104
|
+
* The default profile is `rails` (founder, 2026-10-10): six tools and short
|
|
105
|
+
* instructions that walk a language project end to end. `full` — every
|
|
106
|
+
* tool (queue, atlas, benchmarks, forge, publishing) — is by request:
|
|
107
|
+
* `--profile full` or CHAMPOLLION_MCP_PROFILE=full.
|
|
86
108
|
*
|
|
87
109
|
* @returns {{ start: () => Promise<void> }} Server object with a start method.
|
|
88
110
|
*/
|
|
89
|
-
export async function createServer() {
|
|
111
|
+
export async function createServer({ profile = process.env.CHAMPOLLION_MCP_PROFILE || 'rails' } = {}) {
|
|
90
112
|
// Resolve paths relative to this file (for reading instructions.md,
|
|
91
113
|
// CONTRIBUTING.md, etc.). Computed before server creation because the
|
|
92
114
|
// server's `instructions` are loaded from disk at construction time.
|
|
93
115
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
94
116
|
const repoRoot = resolve(__dirname, '..', '..');
|
|
95
117
|
|
|
118
|
+
// The rails profile (2026-10-09; the default since 2026-10-10): six tools
|
|
119
|
+
// and short instructions a small agent can hold — the language-project
|
|
120
|
+
// journey, end to end. The full profile below is unchanged.
|
|
121
|
+
if (profile === 'rails') return createRailsServer(__dirname);
|
|
122
|
+
if (profile !== 'full') {
|
|
123
|
+
throw new Error(`unknown MCP profile "${profile}" (rails or full)`);
|
|
124
|
+
}
|
|
125
|
+
|
|
96
126
|
// Load the agent behavioral guide and hand it to the SDK as the server's
|
|
97
127
|
// `instructions`. The SDK surfaces these in the MCP `initialize` result so
|
|
98
128
|
// connecting clients can show the model server-level guidance. Falls back to
|