run-dmcp 0.1.0 → 0.2.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/README.md +76 -10
- package/dist/bin/run-dmcp.d.ts +2 -0
- package/dist/bin/run-dmcp.js +55 -0
- package/dist/db/connection.d.ts +32 -0
- package/dist/db/connection.js +38 -16
- package/dist/db/schema.d.ts +29 -1
- package/dist/db/schema.js +439 -7
- package/dist/http/server.js +3 -3
- package/dist/index.d.ts +36 -2
- package/dist/index.js +184 -92
- package/dist/mcp-server.d.ts +49 -0
- package/dist/mcp-server.js +127 -0
- package/dist/reader/turnReader.d.ts +185 -0
- package/dist/reader/turnReader.js +288 -0
- package/dist/register/batch.js +5 -79
- package/dist/register/mcp-resources.d.ts +9 -0
- package/dist/register/mcp-resources.js +16 -62
- package/dist/register/render.d.ts +17 -0
- package/dist/register/render.js +50 -0
- package/dist/register/resolve.d.ts +14 -0
- package/dist/register/resolve.js +102 -0
- package/dist/register/resources.js +11 -4
- package/dist/register/timeline.d.ts +2 -0
- package/dist/register/timeline.js +311 -0
- package/dist/rpg/index.d.ts +29 -0
- package/dist/rpg/index.js +55 -0
- package/dist/rpg/register/abilities.d.ts +2 -0
- package/dist/rpg/register/abilities.js +165 -0
- package/dist/rpg/register/batch.d.ts +2 -0
- package/dist/rpg/register/batch.js +92 -0
- package/dist/rpg/register/combat.d.ts +2 -0
- package/dist/rpg/register/combat.js +207 -0
- package/dist/rpg/register/mcp-prompts.d.ts +2 -0
- package/dist/rpg/register/mcp-prompts.js +684 -0
- package/dist/rpg/register/mcp-resources.d.ts +2 -0
- package/dist/rpg/register/mcp-resources.js +61 -0
- package/dist/rpg/register/quests.d.ts +2 -0
- package/dist/rpg/register/quests.js +118 -0
- package/dist/rpg/register/status.d.ts +2 -0
- package/dist/rpg/register/status.js +130 -0
- package/dist/rpg/register/tables.d.ts +2 -0
- package/dist/rpg/register/tables.js +146 -0
- package/dist/rpg/tools/ability.d.ts +48 -0
- package/dist/rpg/tools/ability.js +238 -0
- package/dist/rpg/tools/combat.d.ts +13 -0
- package/dist/rpg/tools/combat.js +195 -0
- package/dist/rpg/tools/dice.d.ts +23 -0
- package/dist/rpg/tools/dice.js +111 -0
- package/dist/rpg/tools/quest.d.ts +34 -0
- package/dist/rpg/tools/quest.js +164 -0
- package/dist/rpg/tools/status.d.ts +36 -0
- package/dist/rpg/tools/status.js +218 -0
- package/dist/rpg/tools/tables.d.ts +33 -0
- package/dist/rpg/tools/tables.js +209 -0
- package/dist/schemas/index.d.ts +12 -12
- package/dist/timeline/adjudication.d.ts +150 -0
- package/dist/timeline/adjudication.js +174 -0
- package/dist/timeline/changes.d.ts +100 -0
- package/dist/timeline/changes.js +161 -0
- package/dist/timeline/checkpoint.d.ts +69 -0
- package/dist/timeline/checkpoint.js +131 -0
- package/dist/timeline/clock.d.ts +89 -0
- package/dist/timeline/clock.js +173 -0
- package/dist/timeline/constrained.d.ts +220 -0
- package/dist/timeline/constrained.js +671 -0
- package/dist/timeline/export.d.ts +171 -0
- package/dist/timeline/export.js +329 -0
- package/dist/timeline/irreversible.d.ts +85 -0
- package/dist/timeline/irreversible.js +108 -0
- package/dist/timeline/kinds.d.ts +14 -0
- package/dist/timeline/kinds.js +22 -0
- package/dist/timeline/narration.d.ts +175 -0
- package/dist/timeline/narration.js +259 -0
- package/dist/timeline/projection.d.ts +97 -0
- package/dist/timeline/projection.js +330 -0
- package/dist/timeline/provenance.d.ts +66 -0
- package/dist/timeline/provenance.js +45 -0
- package/dist/timeline/registry.d.ts +95 -0
- package/dist/timeline/registry.js +124 -0
- package/dist/timeline/render.d.ts +121 -0
- package/dist/timeline/render.js +187 -0
- package/dist/timeline/replay.d.ts +64 -0
- package/dist/timeline/replay.js +104 -0
- package/dist/timeline/resolve.d.ts +262 -0
- package/dist/timeline/resolve.js +226 -0
- package/dist/timeline/schema.d.ts +13 -0
- package/dist/timeline/schema.js +262 -0
- package/dist/timeline/t.d.ts +80 -0
- package/dist/timeline/t.js +37 -0
- package/dist/tools/constraint.d.ts +44 -80
- package/dist/tools/constraint.js +115 -124
- package/dist/tools/relationship.d.ts +83 -2
- package/dist/tools/relationship.js +139 -62
- package/dist/tools/resource.d.ts +31 -6
- package/dist/tools/resource.js +106 -153
- package/dist/types/index.d.ts +19 -1
- package/dist/utils/output-schemas.d.ts +593 -2
- package/dist/utils/output-schemas.js +3 -0
- package/dist/utils/webui.d.ts +32 -0
- package/dist/utils/webui.js +54 -1
- package/package.json +20 -4
- package/dist/__tests__/engineVocabulary.test.d.ts +0 -1
- package/dist/__tests__/engineVocabulary.test.js +0 -147
- package/dist/db/__tests__/connection.test.d.ts +0 -1
- package/dist/db/__tests__/connection.test.js +0 -72
- package/dist/db/__tests__/testDb.d.ts +0 -33
- package/dist/db/__tests__/testDb.js +0 -41
- package/dist/test-setup.d.ts +0 -1
- package/dist/test-setup.js +0 -13
- package/dist/tools/__tests__/audio.test.d.ts +0 -1
- package/dist/tools/__tests__/audio.test.js +0 -59
- package/dist/tools/__tests__/conserved.test.d.ts +0 -1
- package/dist/tools/__tests__/conserved.test.js +0 -488
- package/dist/tools/__tests__/constraint.test.d.ts +0 -1
- package/dist/tools/__tests__/constraint.test.js +0 -212
- package/dist/tools/__tests__/expiry-consequences.test.d.ts +0 -1
- package/dist/tools/__tests__/expiry-consequences.test.js +0 -110
- package/dist/tools/__tests__/images.test.d.ts +0 -1
- package/dist/tools/__tests__/images.test.js +0 -59
- package/dist/tools/__tests__/relationship.test.d.ts +0 -1
- package/dist/tools/__tests__/relationship.test.js +0 -132
- package/dist/tools/__tests__/resource-constraints.test.d.ts +0 -1
- package/dist/tools/__tests__/resource-constraints.test.js +0 -131
- package/dist/tools/__tests__/resource.test.d.ts +0 -1
- package/dist/tools/__tests__/resource.test.js +0 -190
- package/dist/tools/__tests__/time.test.d.ts +0 -1
- package/dist/tools/__tests__/time.test.js +0 -404
- package/dist/tools/__tests__/timers.test.d.ts +0 -1
- package/dist/tools/__tests__/timers.test.js +0 -426
- package/dist/tools/__tests__/world.test.d.ts +0 -1
- package/dist/tools/__tests__/world.test.js +0 -70
- package/dist/utils/__tests__/json.test.d.ts +0 -1
- package/dist/utils/__tests__/json.test.js +0 -55
- package/dist/utils/__tests__/validation.test.d.ts +0 -1
- package/dist/utils/__tests__/validation.test.js +0 -90
package/dist/index.js
CHANGED
|
@@ -1,92 +1,184 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
// The library entry point: exports, and nothing else.
|
|
2
|
+
//
|
|
3
|
+
// Importing this module must do nothing to the machine -- no database file, no
|
|
4
|
+
// listener, no transport, no timer, no work of any kind. 0.1.0 shipped one
|
|
5
|
+
// entry that was both library and application, so importing the package opened
|
|
6
|
+
// a database inside node_modules and bound the web UI's port, and the listener
|
|
7
|
+
// outlived the import by hours.
|
|
8
|
+
//
|
|
9
|
+
// The rule is asserted from the outside in src/__tests__/entrypoints.test.ts:
|
|
10
|
+
// a child process imports this file and must be able to EXIT. Anything left
|
|
11
|
+
// open keeps it alive and fails the test, so the guarantee does not depend on
|
|
12
|
+
// anyone remembering to enumerate what must not start.
|
|
13
|
+
//
|
|
14
|
+
// Starting things is src/bin/run-dmcp.ts, which is what `bin` points at.
|
|
15
|
+
//
|
|
16
|
+
// THIS PACKAGE ROOT IS THE CORE (design §8, issue #17): entities, facts,
|
|
17
|
+
// events, the timeline, and the entity/property domains a consumer cannot
|
|
18
|
+
// lose without losing its own spine -- resources, relationships, factions,
|
|
19
|
+
// secrets, locations, items. Dice, combat, abilities, status effects, random
|
|
20
|
+
// tables and quests are genuinely game-shaped, and they are an OPTIONAL
|
|
21
|
+
// layer above this, not part of it: import "run-dmcp/rpg" for
|
|
22
|
+
// `createMcpServer`, the full assembly this package used to export under
|
|
23
|
+
// that name. That is design §8's line, not an inversion of it -- the core
|
|
24
|
+
// stays importable, buildable and useful with nothing above it, and the
|
|
25
|
+
// layer stays free to depend down into the core without the core ever
|
|
26
|
+
// depending up into it. `src/__tests__/layerBoundary.test.ts` walks the
|
|
27
|
+
// static import graph from this file and fails if anything under `src/rpg/`
|
|
28
|
+
// is reachable from it.
|
|
29
|
+
export { createCoreMcpServer, SERVER_NAME, SERVER_VERSION } from "./mcp-server.js";
|
|
30
|
+
// The database, and where it lives. The path resolves against the consuming
|
|
31
|
+
// application (DMCP_DB_PATH, else an existing XDG data directory, else the
|
|
32
|
+
// working directory) and never against this package's install location.
|
|
33
|
+
export { getDatabase, closeDatabase, withTransaction, getDatabasePath, getDataDir, resolveDataPathFrom, } from "./db/connection.js";
|
|
34
|
+
// The schema, and the hook a consuming application uses to bring up its own
|
|
35
|
+
// tables in the same startup pass, in the same database, under the same rules.
|
|
36
|
+
export { initializeSchema } from "./db/schema.js";
|
|
37
|
+
// The timeline (design §5.1) -- the reason this engine exists, and therefore
|
|
38
|
+
// something a consuming application reaches directly rather than only through
|
|
39
|
+
// a tool call. `replay` answers what the world looked like at any `t`;
|
|
40
|
+
// `declareTimeAxis` is where an application says what its `t` actually is,
|
|
41
|
+
// which it must do before its first write for that game if it wants its own
|
|
42
|
+
// origin (see clock.ts).
|
|
43
|
+
//
|
|
44
|
+
// `timelineDivergences` is exported for the same reason design §13 makes it a
|
|
45
|
+
// stop condition rather than a nicety: an application that keeps its world
|
|
46
|
+
// here is entitled to ask, of its own database, whether the log it is trusting
|
|
47
|
+
// still reproduces its live tables. It returns rows and never a verdict.
|
|
48
|
+
export { replay } from "./timeline/replay.js";
|
|
49
|
+
export { declareTimeAxis, setStoryTime, currentStoryTime } from "./timeline/clock.js";
|
|
50
|
+
// `changes_within(t0, t1)` (design §5.5) -- the range companion to `replay`,
|
|
51
|
+
// for a consumer whose units have duration rather than instants. It returns
|
|
52
|
+
// transitions and never a verdict: one caller reads a change inside a window
|
|
53
|
+
// as a defect, another reads the same rows to build a summary of what has
|
|
54
|
+
// happened since it last looked. Same primitive, opposite readings, which is
|
|
55
|
+
// how you can tell it belongs in the core rather than to whoever asked first.
|
|
56
|
+
export { changesWithin } from "./timeline/changes.js";
|
|
57
|
+
export { compareT, assertT } from "./timeline/t.js";
|
|
58
|
+
export { timelineDivergences } from "./timeline/checkpoint.js";
|
|
59
|
+
// `irreversible` (design §5.3) -- the temporal member of the constraint family.
|
|
60
|
+
// Exported because the enforcement is structural (triggers on `facts`), which
|
|
61
|
+
// means an application never calls a checker: it declares, and later
|
|
62
|
+
// contradictions are refused at the write that attempts them. What it does need
|
|
63
|
+
// from here is the declaration itself, and the ability to ask which facts carry
|
|
64
|
+
// it -- with the one hop of provenance (§5.2c) that makes a refusal reviewable
|
|
65
|
+
// rather than merely obeyed.
|
|
66
|
+
export { declareIrreversible, irreversibleFactFor, listIrreversibleFacts, } from "./timeline/irreversible.js";
|
|
67
|
+
export { openingEventId } from "./timeline/provenance.js";
|
|
68
|
+
// The narration constraint (design §5.2b/§5.2c, GitHub issues #11 and #12)
|
|
69
|
+
// -- the outbound half of authority, and the half with two consumers.
|
|
70
|
+
// "Here is what is true; depict it, do not argue with it." Exported as a
|
|
71
|
+
// library function FIRST, before any MCP tool wraps it (the one tool that
|
|
72
|
+
// does, `narration_constraint_at`, is a thin JSON-over-stdio wrapper around
|
|
73
|
+
// this same call), because the consumer that most needs it is a process
|
|
74
|
+
// that must never call a model at runtime: its units have duration and
|
|
75
|
+
// everything in them is already known in advance, so its narrator output
|
|
76
|
+
// is generated once, reviewed by a human, committed as a file, and
|
|
77
|
+
// rendered hours later by a lint over that finished artifact, with no
|
|
78
|
+
// engine and no model in the loop (§6's "library functions first, MCP
|
|
79
|
+
// tools second," restated here because this is the export where it matters
|
|
80
|
+
// most). `contradictions` is exported alongside it for the same reason and
|
|
81
|
+
// takes no database handle at all -- it is a pure function over the plain
|
|
82
|
+
// object `narrationConstraintAt` returns, so a caller can serialize a
|
|
83
|
+
// constraint once, hand the JSON to an entirely separate process, and run
|
|
84
|
+
// the check there hours or days later. Prohibitions in the returned shape
|
|
85
|
+
// are derived and structural, never authored and lexical (hard rule 5): the
|
|
86
|
+
// engine records that a fact holds and lets a claim disagree or not,
|
|
87
|
+
// exactly the way `changes_within` (§5.5) records transitions rather than a
|
|
88
|
+
// verdict -- there is no `mustNotSay`, no severity, nothing this project's
|
|
89
|
+
// four recorded negative-prompt failures would recognise.
|
|
90
|
+
export { narrationConstraintAt, contradictions, NARRATION_CONSTRAINT_FORMAT_VERSION, } from "./timeline/narration.js";
|
|
91
|
+
// The constrained-write choke point (design §5.4 option (C)) -- the one place
|
|
92
|
+
// a constrained numeric fact key changes, and the reason there is no longer a
|
|
93
|
+
// `resource_history` table beside the timeline answering the same question.
|
|
94
|
+
// Exported because an application that keeps invariant-bearing numbers here
|
|
95
|
+
// has to be able to write them, and writing them anywhere else is precisely
|
|
96
|
+
// the second path option (C) exists to close: a direct UPDATE still lands in
|
|
97
|
+
// `facts` (the projection triggers see to that), but it arrives unchecked and
|
|
98
|
+
// unannotated.
|
|
99
|
+
//
|
|
100
|
+
// `valueHistory` is the read half, and it is deliberately not a separate
|
|
101
|
+
// mechanism -- it is `facts` and `events`, assembled. It returns rows and
|
|
102
|
+
// never a verdict.
|
|
103
|
+
//
|
|
104
|
+
// `ConstraintViolationError` is exported because a refusal is only reviewable
|
|
105
|
+
// if the caller can tell it apart from a failure. For the `irreversible`
|
|
106
|
+
// member it carries §5.2c's one hop -- the contradicted fact, its
|
|
107
|
+
// `valid_from_t`, and the event that opened it -- so a reviewer can answer
|
|
108
|
+
// "is the fact wrong, or is the claim wrong", which is undecidable without it.
|
|
109
|
+
export { writeConstrainedValue, transferConstrainedValue, valueHistory, } from "./timeline/constrained.js";
|
|
110
|
+
export { ConstraintViolationError, constraintsFor, conservedConstraintFor } from "./timeline/registry.js";
|
|
111
|
+
// The resolve protocol (design §5.2a, GitHub issue #10) -- the inbound half of
|
|
112
|
+
// authority. The engine enforces the PROTOCOL -- resolution happens before
|
|
113
|
+
// narration, writes go through the audited path, declared expectations are
|
|
114
|
+
// checked -- without knowing what any particular mechanic MEANS. An application
|
|
115
|
+
// registers its mechanics by passing them to `createResolver`, and the engine
|
|
116
|
+
// dispatches them and never learns their names.
|
|
117
|
+
//
|
|
118
|
+
// Registration is injection at construction, exactly like `initializeSchema({
|
|
119
|
+
// migrations })` and for exactly the same reason: a global registry would make
|
|
120
|
+
// behaviour depend on module import order and on side effects at import time,
|
|
121
|
+
// which is the disease the entry-point split above cured. A parameter cannot be
|
|
122
|
+
// registered too late.
|
|
123
|
+
//
|
|
124
|
+
// NOTE WHAT IS DELIBERATELY *NOT* EXPORTED HERE: `withAdjudicationOpen` and
|
|
125
|
+
// `adjudicationOpen` (./timeline/adjudication.js). `resolve_only` (issue #13)
|
|
126
|
+
// means a value moves only through an adjudicating call, and the adjudication
|
|
127
|
+
// window is what "adjudicating" is measured against -- so exporting the ability
|
|
128
|
+
// to open one would hand every caller a one-line bypass of the constraint, and
|
|
129
|
+
// the fourth member of the family would be enforced against everybody except
|
|
130
|
+
// whoever read the export list. `resolver.resolve()` is the only public door to
|
|
131
|
+
// a `resolve_only` value. That is the whole point of the constraint, so the
|
|
132
|
+
// window stays internal to the engine that opens it.
|
|
133
|
+
export { createResolver, ResolveProtocolError } from "./timeline/resolve.js";
|
|
134
|
+
// The state-to-text projection (design §7, GitHub issue #16) -- "say what IS
|
|
135
|
+
// true, never what is absent."
|
|
136
|
+
//
|
|
137
|
+
// What is exported here is the MECHANISM and the TYPE of a vocabulary. There
|
|
138
|
+
// is deliberately no vocabulary value, no default and no example anywhere in
|
|
139
|
+
// this package: a vocabulary rich enough to render a real world contains a
|
|
140
|
+
// caller's own nouns, and either sitting in the engine would fail
|
|
141
|
+
// `engineVocabulary.test.ts` on day one -- correctly (§7's closing paragraph,
|
|
142
|
+
// §10). `RenderVocabulary` is a parameter type; a caller supplies the words.
|
|
143
|
+
//
|
|
144
|
+
// The rule is enforced at CONSTRUCTION and never by scanning output.
|
|
145
|
+
// `createStateRenderer` refuses a vocabulary entry carrying any field but
|
|
146
|
+
// `noun` and `adjectives`, by name -- which is what stops an `avoid:` or a
|
|
147
|
+
// `negate:` being bolted on later -- and the renderer's only source of state
|
|
148
|
+
// is `replay(t)`, so a fact that does not hold produces NOTHING rather than a
|
|
149
|
+
// phrase about its absence. There is no differential form and never will be:
|
|
150
|
+
// nothing here takes two `t`s, because "render the change between these two
|
|
151
|
+
// states" is precisely the shape that produces "no longer" (hard rules 3 and
|
|
152
|
+
// 4; the four recorded negative-prompt failures across two codebases).
|
|
153
|
+
export { createStateRenderer } from "./timeline/render.js";
|
|
154
|
+
// The turn reader (design §12 seam 3, GitHub issue #15) -- one model call per
|
|
155
|
+
// unit of progress, answering the questions a server cannot answer with code.
|
|
156
|
+
//
|
|
157
|
+
// The engine owns the call, the citation rule, coercion to keys that actually
|
|
158
|
+
// exist, the safe-direction default and the fallback ladder; the caller owns
|
|
159
|
+
// the questions and the key vocabulary they are answered in. Answers come back
|
|
160
|
+
// as KEYS, never prose.
|
|
161
|
+
//
|
|
162
|
+
// NOTE WHAT IS NOT HERE, BECAUSE IT IS THE POINT: no transport. A
|
|
163
|
+
// `ReaderTransport` is a plain async function the CALLER writes and injects,
|
|
164
|
+
// so this package contains no vendor SDK, no API key, no endpoint, and no
|
|
165
|
+
// network code of any kind -- enforced mechanically by
|
|
166
|
+
// `src/reader/__tests__/noVendorTransports.test.ts`, which scans this
|
|
167
|
+
// directory for vendor and credential tokens the way the vocabulary test
|
|
168
|
+
// scans for a consumer's language. The engine is provably ignorant of what is
|
|
169
|
+
// on the other end of a rung, which is also why the ladder's ORDER is the
|
|
170
|
+
// caller's: it never learns which rung is local and which is hosted.
|
|
171
|
+
export { createTurnReader } from "./reader/turnReader.js";
|
|
172
|
+
// Timeline export (design §6) -- the boundary that keeps both halves honest:
|
|
173
|
+
// conversational authoring upstream of a frozen artifact, deterministic
|
|
174
|
+
// consumers downstream of it. These are exported as library functions first
|
|
175
|
+
// and served as MCP tools second, because the consumer that most needs them
|
|
176
|
+
// is a process that must never call a model at runtime.
|
|
177
|
+
export { exportTimeline, importTimeline, exportTimelineToFile, importTimelineFromFile, TIMELINE_FORMAT_VERSION, } from "./timeline/export.js";
|
|
178
|
+
export { ENTITY_KINDS } from "./timeline/kinds.js";
|
|
179
|
+
// The web UI's port helpers -- no RPG dependency, so they stay here. The web
|
|
180
|
+
// UI server itself (`createHttpServer`/`startHttpServer`) imports quest,
|
|
181
|
+
// ability and combat tools and is exported from "run-dmcp/rpg" instead
|
|
182
|
+
// (src/rpg/index.ts), even though the file that implements it stays at
|
|
183
|
+
// src/http/server.ts on disk.
|
|
184
|
+
export { DEFAULT_HTTP_PORT, httpPortFromEnv, webUiEnabled, setHttpPort, getWebUiBaseUrl, } from "./utils/webui.js";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type Mechanic } from "./timeline/resolve.js";
|
|
3
|
+
import { type RenderVocabulary } from "./timeline/render.js";
|
|
4
|
+
export declare const SERVER_NAME = "dmcp";
|
|
5
|
+
export declare const SERVER_VERSION = "0.2.0";
|
|
6
|
+
/**
|
|
7
|
+
* Build an MCP server with every CORE tool, resource and prompt this engine
|
|
8
|
+
* serves -- entities, facts, events, the timeline, and the entity/property
|
|
9
|
+
* domains (resources, relationships, factions, secrets, locations, items)
|
|
10
|
+
* design §8 keeps out of the RPG layer because a consumer that lost them
|
|
11
|
+
* would have to drag that layer back in to get them. No dice, no combat, no
|
|
12
|
+
* abilities, no status effects, no random tables, no quests, and no
|
|
13
|
+
* game-master prompt library -- those are `registerRpgTools` in
|
|
14
|
+
* src/rpg/index.ts, which calls this function first and adds its layer on
|
|
15
|
+
* top of what it returns. `createMcpServer` there is the full assembly this
|
|
16
|
+
* function used to be, under the same name, with the same behaviour, so
|
|
17
|
+
* nothing that already depends on the full server sees any difference.
|
|
18
|
+
*
|
|
19
|
+
* The returned server is not connected to anything. Connect it to a transport
|
|
20
|
+
* yourself, and call `initializeSchema()` before serving a request -- both are
|
|
21
|
+
* the caller's to decide, and neither happens on import.
|
|
22
|
+
*
|
|
23
|
+
* `mechanics` (design §5.2a, issue #10) is injection at construction, the
|
|
24
|
+
* same way `initializeSchema({ migrations })` (src/db/schema.ts) is -- there
|
|
25
|
+
* is no global resolver anywhere in this codebase, only the one a caller
|
|
26
|
+
* builds by passing its mechanics here. Every existing zero-argument call
|
|
27
|
+
* site (src/bin/run-dmcp.ts, via src/rpg/index.ts) keeps working unchanged:
|
|
28
|
+
* `options` and `options.mechanics` are both optional, and calling
|
|
29
|
+
* `createCoreMcpServer()` with nothing at all registers every core tool this
|
|
30
|
+
* engine serves and no resolve surface. That absence is deliberate, not an
|
|
31
|
+
* oversight -- an engine with no mechanics registered has nothing a
|
|
32
|
+
* `resolve` tool could ever dispatch, so it gets no `resolve`/`list_mechanics`
|
|
33
|
+
* tools rather than a pair that could only ever answer "unknown-mechanic"
|
|
34
|
+
* and "[]".
|
|
35
|
+
*
|
|
36
|
+
* `vocabulary` (design §7, issue #16) is injected the same way and for the
|
|
37
|
+
* same reason -- and here the injection is not merely a style choice, it is
|
|
38
|
+
* the design's own line: the state-to-text projection's MECHANISM is core,
|
|
39
|
+
* and the NOUNS it may emit belong to each caller. A vocabulary rich enough
|
|
40
|
+
* to render a real world would fail this engine's vocabulary hygiene test on
|
|
41
|
+
* day one, correctly, so this package ships none and there is no default to
|
|
42
|
+
* fall back to. An engine with no vocabulary injected has nothing it could
|
|
43
|
+
* name, so it registers no `render_state_at` tool at all -- the identical
|
|
44
|
+
* shape (and the identical silence) as `mechanics` above.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createCoreMcpServer(options?: {
|
|
47
|
+
mechanics?: readonly Mechanic[];
|
|
48
|
+
vocabulary?: RenderVocabulary;
|
|
49
|
+
}): McpServer;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// The CORE MCP server, built but not started.
|
|
2
|
+
//
|
|
3
|
+
// This module exists so that "which tools does this engine serve" is separable
|
|
4
|
+
// from "and now go listen on stdio and bind a port". Constructing the server
|
|
5
|
+
// opens no database, binds no port and connects no transport; a caller decides
|
|
6
|
+
// all three. src/bin/run-dmcp.ts is the caller that decides them the way an
|
|
7
|
+
// application would.
|
|
8
|
+
//
|
|
9
|
+
// This is the CORE half of design §8's split (issue #17): entities, facts,
|
|
10
|
+
// events, the timeline, resource/relationship/faction/secret/location/item
|
|
11
|
+
// concepts, and the resolve/render/timeline surfaces that sit on top of them.
|
|
12
|
+
// Dice, combat, abilities, status effects, random tables and quests are
|
|
13
|
+
// genuinely game-shaped and live one layer up, in src/rpg/index.ts, which
|
|
14
|
+
// calls `registerRpgTools(server)` on a server this file already built.
|
|
15
|
+
// `createMcpServer` (the full assembly, unchanged in name and behaviour from
|
|
16
|
+
// before the split) lives there too now, not here -- this file only knows
|
|
17
|
+
// how to build the core.
|
|
18
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19
|
+
// Import registration functions
|
|
20
|
+
import { registerCoreTools } from "./register/core.js";
|
|
21
|
+
import { registerWorldTools } from "./register/world.js";
|
|
22
|
+
import { registerCharacterTools } from "./register/character.js";
|
|
23
|
+
import { registerInventoryTools } from "./register/inventory.js";
|
|
24
|
+
import { registerNarrativeTools } from "./register/narrative.js";
|
|
25
|
+
import { registerResourceTools } from "./register/resources.js";
|
|
26
|
+
import { registerTimeTools } from "./register/time.js";
|
|
27
|
+
import { registerSecretTools } from "./register/secrets.js";
|
|
28
|
+
import { registerRelationshipTools } from "./register/relationships.js";
|
|
29
|
+
import { registerTagTools } from "./register/tags.js";
|
|
30
|
+
import { registerFactionTools } from "./register/factions.js";
|
|
31
|
+
import { registerNoteTools } from "./register/notes.js";
|
|
32
|
+
import { registerPauseTools } from "./register/pause.js";
|
|
33
|
+
import { registerImageTools } from "./register/images.js";
|
|
34
|
+
import { registerAudioTools } from "./register/audio.js";
|
|
35
|
+
import { registerDisplayTools } from "./register/display.js";
|
|
36
|
+
import { registerBatchTools } from "./register/batch.js";
|
|
37
|
+
import { registerMcpResources } from "./register/mcp-resources.js";
|
|
38
|
+
import { registerTimelineTools } from "./register/timeline.js";
|
|
39
|
+
import { registerResolveTools } from "./register/resolve.js";
|
|
40
|
+
import { registerRenderTools } from "./register/render.js";
|
|
41
|
+
import { createResolver } from "./timeline/resolve.js";
|
|
42
|
+
import { createStateRenderer } from "./timeline/render.js";
|
|
43
|
+
export const SERVER_NAME = "dmcp";
|
|
44
|
+
export const SERVER_VERSION = "0.2.0";
|
|
45
|
+
/**
|
|
46
|
+
* Build an MCP server with every CORE tool, resource and prompt this engine
|
|
47
|
+
* serves -- entities, facts, events, the timeline, and the entity/property
|
|
48
|
+
* domains (resources, relationships, factions, secrets, locations, items)
|
|
49
|
+
* design §8 keeps out of the RPG layer because a consumer that lost them
|
|
50
|
+
* would have to drag that layer back in to get them. No dice, no combat, no
|
|
51
|
+
* abilities, no status effects, no random tables, no quests, and no
|
|
52
|
+
* game-master prompt library -- those are `registerRpgTools` in
|
|
53
|
+
* src/rpg/index.ts, which calls this function first and adds its layer on
|
|
54
|
+
* top of what it returns. `createMcpServer` there is the full assembly this
|
|
55
|
+
* function used to be, under the same name, with the same behaviour, so
|
|
56
|
+
* nothing that already depends on the full server sees any difference.
|
|
57
|
+
*
|
|
58
|
+
* The returned server is not connected to anything. Connect it to a transport
|
|
59
|
+
* yourself, and call `initializeSchema()` before serving a request -- both are
|
|
60
|
+
* the caller's to decide, and neither happens on import.
|
|
61
|
+
*
|
|
62
|
+
* `mechanics` (design §5.2a, issue #10) is injection at construction, the
|
|
63
|
+
* same way `initializeSchema({ migrations })` (src/db/schema.ts) is -- there
|
|
64
|
+
* is no global resolver anywhere in this codebase, only the one a caller
|
|
65
|
+
* builds by passing its mechanics here. Every existing zero-argument call
|
|
66
|
+
* site (src/bin/run-dmcp.ts, via src/rpg/index.ts) keeps working unchanged:
|
|
67
|
+
* `options` and `options.mechanics` are both optional, and calling
|
|
68
|
+
* `createCoreMcpServer()` with nothing at all registers every core tool this
|
|
69
|
+
* engine serves and no resolve surface. That absence is deliberate, not an
|
|
70
|
+
* oversight -- an engine with no mechanics registered has nothing a
|
|
71
|
+
* `resolve` tool could ever dispatch, so it gets no `resolve`/`list_mechanics`
|
|
72
|
+
* tools rather than a pair that could only ever answer "unknown-mechanic"
|
|
73
|
+
* and "[]".
|
|
74
|
+
*
|
|
75
|
+
* `vocabulary` (design §7, issue #16) is injected the same way and for the
|
|
76
|
+
* same reason -- and here the injection is not merely a style choice, it is
|
|
77
|
+
* the design's own line: the state-to-text projection's MECHANISM is core,
|
|
78
|
+
* and the NOUNS it may emit belong to each caller. A vocabulary rich enough
|
|
79
|
+
* to render a real world would fail this engine's vocabulary hygiene test on
|
|
80
|
+
* day one, correctly, so this package ships none and there is no default to
|
|
81
|
+
* fall back to. An engine with no vocabulary injected has nothing it could
|
|
82
|
+
* name, so it registers no `render_state_at` tool at all -- the identical
|
|
83
|
+
* shape (and the identical silence) as `mechanics` above.
|
|
84
|
+
*/
|
|
85
|
+
export function createCoreMcpServer(options) {
|
|
86
|
+
const server = new McpServer({
|
|
87
|
+
name: SERVER_NAME,
|
|
88
|
+
version: SERVER_VERSION,
|
|
89
|
+
});
|
|
90
|
+
// Register all core tools by domain
|
|
91
|
+
registerCoreTools(server); // Game, Interview, Rules
|
|
92
|
+
registerWorldTools(server); // Locations, Connections, Map
|
|
93
|
+
registerCharacterTools(server); // Characters (PC/NPC)
|
|
94
|
+
registerInventoryTools(server); // Items
|
|
95
|
+
registerNarrativeTools(server); // Events, History, Export, Player Choices
|
|
96
|
+
registerResourceTools(server); // Custom Resources
|
|
97
|
+
registerTimeTools(server); // Calendar, Time, Timers
|
|
98
|
+
registerSecretTools(server); // Secrets, Knowledge
|
|
99
|
+
registerRelationshipTools(server); // Relationships
|
|
100
|
+
registerTagTools(server); // Tags
|
|
101
|
+
registerFactionTools(server); // Factions
|
|
102
|
+
registerNoteTools(server); // Game Notes
|
|
103
|
+
registerPauseTools(server); // Pause/Resume, Context Snapshots, External Updates
|
|
104
|
+
registerImageTools(server); // Stored Images
|
|
105
|
+
registerAudioTools(server); // Stored Audio (TTS, Voice References)
|
|
106
|
+
registerDisplayTools(server); // Display/Theme Configuration
|
|
107
|
+
registerBatchTools(server); // Batch Operations (multi-entity, workflows -- entity/property only)
|
|
108
|
+
registerTimelineTools(server); // replay(t), story-time axis declaration
|
|
109
|
+
const mechanics = options?.mechanics;
|
|
110
|
+
if (mechanics && mechanics.length > 0) {
|
|
111
|
+
const resolver = createResolver({ mechanics });
|
|
112
|
+
registerResolveTools(server, resolver); // resolve(), list_mechanics -- only when mechanics are registered
|
|
113
|
+
}
|
|
114
|
+
const vocabulary = options?.vocabulary;
|
|
115
|
+
if (vocabulary) {
|
|
116
|
+
// Built here rather than accepted pre-built so the vocabulary is
|
|
117
|
+
// validated at construction of the SERVER too, not merely at
|
|
118
|
+
// construction of a renderer a caller might have made anywhere:
|
|
119
|
+
// `createStateRenderer` throws on a malformed vocabulary, so a server
|
|
120
|
+
// that would have served an unnameable projection never comes up.
|
|
121
|
+
registerRenderTools(server, createStateRenderer({ vocabulary })); // render_state_at -- only when a vocabulary is injected
|
|
122
|
+
}
|
|
123
|
+
// Register core MCP Resources (RPG resources -- game-quests, quest -- are
|
|
124
|
+
// registered by registerRpgMcpResources, one layer up)
|
|
125
|
+
registerMcpResources(server); // Read-only data access via URI
|
|
126
|
+
return server;
|
|
127
|
+
}
|