Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
971eefe
docs(rfc-003): canonical MCP implementation blueprint (omnigraph-mcp …
ragnorc Jun 10, 2026
6fc92ca
docs(rfc-003): correct-by-construction fixes from PR review
ragnorc Jun 11, 2026
61c18b6
docs(rfc-003): validate against main; fold the implementation spec in
ragnorc Jun 13, 2026
20233a3
docs(rfc-003): standalone MCP surface spec, validated against upstream
ragnorc Jun 13, 2026
de9e28e
docs(rfc-003): document the per-graph multi-graph MCP model
ragnorc Jun 13, 2026
c08e8db
Merge remote-tracking branch 'origin/main' into ragnorc/omnigraph-mcp…
ragnorc Jun 16, 2026
3771a29
docs(rfc-003): align with main after merge (cluster-only, api-types, …
ragnorc Jun 16, 2026
86fbb62
docs(rfc-003): fold external review into correct-by-design fixes
ragnorc Jun 16, 2026
0f58329
docs(rfc-013): tenancy model — cluster-as-tenant cells, pooled compute
ragnorc Jun 16, 2026
c43b81d
docs(rfc-013): add reader/writer scaling (§5.8) — split read fleet vs…
ragnorc Jun 16, 2026
bcd0d9c
feat(mcp): MCP server surface — Streamable-HTTP transport + tool/reso…
ragnorc Jun 17, 2026
c8e91c1
feat(mcp): per-query @mcp(...) annotation + per-param @description + …
ragnorc Jun 17, 2026
c063433
docs(mcp): document the MCP surface, authoring controls, and skill (v…
ragnorc Jun 17, 2026
916dc46
fix(server): align stored-query MCP discovery gates
ragnorc Jun 17, 2026
fbf455a
Merge branch 'main' into ragnorc/omnigraph-mcp-crate
ragnorc Jun 19, 2026
8dab7e2
test(mcp): harden symptomatic MCP fixes to construction-enforced
ragnorc Jun 20, 2026
adc36ad
Merge branch 'main' into ragnorc/omnigraph-mcp-crate
ragnorc Jun 23, 2026
83446cd
docs: drop the tenancy-cells RFC from this PR (unrelated to MCP)
ragnorc Jun 24, 2026
4d4c216
Merge branch 'main' into ragnorc/omnigraph-mcp-crate
ragnorc Jun 25, 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
90 changes: 90 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"crates/omnigraph-cluster",
"crates/omnigraph-policy",
"crates/omnigraph-server",
"crates/omnigraph-mcp",
]
default-members = [
"crates/omnigraph",
Expand Down
4 changes: 4 additions & 0 deletions crates/omnigraph-api-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ omnigraph-compiler = { path = "../omnigraph-compiler", version = "0.7.0" }
serde = { workspace = true }
serde_json = { workspace = true }
utoipa = { workspace = true }

[dev-dependencies]
# Faithful `pattern` enforcement in the schema/coercer equivalence test.
regex = { workspace = true }
64 changes: 63 additions & 1 deletion crates/omnigraph-api-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use omnigraph_compiler::query::ast::Param;
use omnigraph_compiler::result::QueryResult;
use omnigraph_compiler::types::{PropType, ScalarType};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_json::{Value, json};
use utoipa::{IntoParams, ToSchema};

/// Shadow enum for documenting [`LoadMode`] in the OpenAPI schema.
Expand Down Expand Up @@ -459,6 +459,68 @@ pub fn param_descriptor(param: &Param) -> ParamDescriptor {
}
}

/// JSON Schema (2020-12) for a scalar param kind. **Superset of the engine
/// coercer** (`omnigraph_compiler::coerce_param_typed`, Standard mode): a
/// too-narrow schema would make a strict client reject inputs the engine
/// accepts; a too-wide one reaches the coercer and surfaces as an `isError`
/// tool result for model self-correction (SEP-1303). Locked to the coercer by
/// `tests/schema_equivalence.rs`. Exhaustive + wildcard-free: adding a
/// `ParamKind` is a compile error until its arm (and corpus row) exist.
fn scalar_schema(kind: ParamKind) -> Value {
match kind {
ParamKind::String => json!({ "type": "string" }),
ParamKind::Bool => json!({ "type": "boolean" }),
// Standard-mode integer coercion accepts a JSON number OR a numeric
// string (i64/u64 lose precision past 2^53 as a JSON number), so the
// schema accepts both; range/sign are the coercer's to enforce.
ParamKind::Int | ParamKind::BigInt => json!({
"anyOf": [ { "type": "integer" }, { "type": "string", "pattern": r"^-?\d+$" } ]
}),
ParamKind::Float => json!({ "type": "number" }),
// Date/DateTime/Blob coerce from any string; `format` is an advisory
// annotation (non-asserting in 2020-12), so the schema accepts exactly
// what the coercer does while still hinting the shape to clients.
ParamKind::Date => json!({ "type": "string", "format": "date" }),
ParamKind::DateTime => json!({ "type": "string", "format": "date-time" }),
ParamKind::Blob => json!({ "type": "string", "format": "uri" }),
ParamKind::Vector | ParamKind::List => {
unreachable!("composite kinds are handled in param_json_schema")
}
}
}

/// The JSON Schema (2020-12) for a stored-query parameter — the single mapping
/// both the OpenAPI catalog and the MCP tool projection consume, applying the
/// nullable rule uniformly. See [`scalar_schema`] for the superset contract.
pub fn param_json_schema(p: &ParamDescriptor) -> Value {
let base = match p.kind {
ParamKind::Vector => {
let mut schema = json!({ "type": "array", "items": { "type": "number" } });
if let Some(dim) = p.vector_dim {
schema["minItems"] = json!(dim);
schema["maxItems"] = json!(dim);
}
schema
}
ParamKind::List => {
let item = p
.item_kind
.map(scalar_schema)
.unwrap_or_else(|| json!({ "type": "string" }));
json!({ "type": "array", "items": item })
}
scalar => scalar_schema(scalar),
};
// The coercer accepts explicit `null` for a nullable param (and its
// omission); a strict client would reject `null` against the bare scalar.
// Allow null at the schema level for nullable params.
if p.nullable {
json!({ "anyOf": [ base, { "type": "null" } ] })
} else {
base
}
}


#[derive(Debug, Clone, Default, Serialize, Deserialize, ToSchema)]
pub struct SchemaApplyRequest {
Expand Down
Loading
Loading