Skip to content

feat(spec): add CEP-15 Common Tool Schemas#14

Open
ContextVM-org wants to merge 7 commits intomasterfrom
feat/common-schemas
Open

feat(spec): add CEP-15 Common Tool Schemas#14
ContextVM-org wants to merge 7 commits intomasterfrom
feat/common-schemas

Conversation

@ContextVM-org
Copy link
Copy Markdown
Contributor

Abstract

This CEP establishes a standard for defining and discovering common tool schemas in ContextVM. It enables interoperability by allowing multiple servers to implement standardized tool interfaces that clients can recognize and use consistently. Using MCP's _meta field, RFC 8785 for deterministic hashing, and CEP-6 announcements for discovery, this creates a marketplace where users can choose between multiple providers implementing the same standard tool interface.

Discussion and more info in the related issue

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 7, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
contextvm-docs Ready Ready Preview, Comment Apr 29, 2026 3:22pm

@ContextVM-org ContextVM-org changed the title feat(spec): add CEP-TBD Common Tool Schemas feat(spec): add CEP-15 Common Tool Schemas Dec 12, 2025
Comment thread src/content/docs/spec/ceps/cep-21.md Outdated
}
```

**Tag Format**: `["D", "<schema-hash>", "<tool-name>"]` - Indicates this server defines a common tool schema.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean for a server to "define" a tool schema? if these schemas are deterministically hashed then it shouldn't matter which pubkey (server) defines them

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! The original idea behind this distinction was to propose a native coordination layer, bootstrapping, and a signal for trust/reputation. However, after considering it carefully and keeping in mind adversarial scenarios as well, we agree that there is no need for this distinction or the authoritative mechanism. We have just committed a revision of the spec removing the 'D' tag.

Comment thread src/content/docs/spec/ceps/cep-21.md Outdated
"outputSchema": {
// SHOULD match reference schema if present
},
"_meta": {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar question to before. Whats the purpose of referencing where the schema is defined if its addressed by its hash?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this is not possible at the server level, as even if a server implements a common schema, it still needs to define input and output schemas. Keeping them also serves as a verification mechanism that can be used to assert compliance with the schema hash

Comment thread src/content/docs/spec/ceps/cep-21.md Outdated
import { createHash } from "crypto";

const toolSchema = {
name: "translate_text",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure its necessary to hash the name with the input / output schema. if the purpose of the hash is to discover tools that input -> output then the name seems to be unnecessary and would cause the hashes to be different if the tools where named slightly differently

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided to include the name field in the contract as it is a normative field used to build the calls for a specific method. On the other hand, we consciously chose not to include the title and description fields of the tools to allow flexibility and enable operators to define them freely while maintaining the same schema hash

Remove reference server pattern and simplify schema discovery to use
direct schema hashes without authoritative definers. Update announcement
tags to "I" for implemented schemas, eliminating "D" tags and reference
pubkey requirements. Enhance hash calculation notes and verification
flow for better interoperability.
@vitorpamplona
Copy link
Copy Markdown

It would be nice if the I tag were a NIP-73 reference.

@ContextVM-org
Copy link
Copy Markdown
Contributor Author

It would be nice if the I tag were a NIP-73 reference.

Thanks you for the feedback, and I apologize for the delayed response @vitorpamplona, these days have been quite hectic. If I understood correctly, making the I tag a NIP-73 reference would mean declaring them in the NIP-73 document so that CVM servers can be referenced by the nips tags right? I cannot see any clear benefit, right now. Could you point us to why you think it would be beneficial for this specification? I'm not sure if treating the common schema hash as an external reference makes sense. It does make some sense, but currently cannot see any specific benefit, we can change our mind, so please share your rationale. Thanks

@vitorpamplona
Copy link
Copy Markdown

NIP-73 serves as base to link external content into Nostr and make it part of the ecosystem. For instance, you can have NIP-22 comments and NIP-25 reactions about any NIP-73 identifier. It's just a common way of encoding different identifiers in one tag to make it indexable by relays. In that way, people can vote, follow, and discuss schemas directly.

Revise CEP-15 to use NIP-73 compliant 'i' and 'k' tags instead of 'I' for schema discovery,
update examples and queries accordingly, and add NIP-73 as a dependency.
Update CEP-6 to reference CEP-15 for tools list announcements and add it as a dependency.
@ContextVM-org
Copy link
Copy Markdown
Contributor Author

Thanks @vitorpamplona we've just updated the proposal, now it uses NIP-73 Compliant Tags: Replaced uppercase I tags with lowercase i tags and added k tags with value "io.contextvm/common-schema". There is also some comments about this integration in the updated spec. Please let us know if this looks good for you 👍

@abhayguptas
Copy link
Copy Markdown

This is a very interesting proposal. One thing I wanted to clarify is the hashing boundary for canonical schema identification.

The draft says description and title are intentionally excluded from the hash so implementers can describe their services differently while remaining compatible. But if the hash is computed directly from { name, inputSchema, outputSchema? }, then nested description / title fields inside the JSON Schema would still affect the hash unless there is an explicit normalization step before canonicalization.

Would it make sense to define a schema-normalization rule before JCS hashing, so semantically identical schemas do not diverge just because providers use different documentation text?

@ContextVM-org
Copy link
Copy Markdown
Contributor Author

Hey @abhayguptas, thanks for chiming in. Yes, you’re right, the current draft is a bit ambiguous about that. It makes sense to apply a narrow normalization before hashing that recursively removes these documentation oriented fields from the input and output schemas. I’ll update the draft now.

Add schema normalization step to CEP-15 that removes JSON Schema `title` and `description` keywords before hash calculation, enabling compatible tool definitions from different providers to produce identical schema hashes while preserving documentation flexibility.
@abhayguptas
Copy link
Copy Markdown

Following up on our discussion regarding the hashing boundaries in CEP-15, I wanted to document a few edge cases that could cause functionally identical tool schemas to produce divergent hashes.

1. Hash Inconsistency from Non-Functional Fields

Currently, the draft specifies removing title and description. However, JSON Schema allows many other documentation or metadata fields such as examples, default, deprecated, and x- vendor extensions.

Because JCS (RFC 8785) does not delete fields, if Server A includes "examples": ["Paris"] and Server B omits it, JCS will preserve the examples key. This results in different hashes for functionally identical tools.

Proposal: We should expand the normalization step to explicitly strip examples, default, deprecated, and x-* fields before passing the object to JCS.

2. $ref Handling in Schemas

If a tool's inputSchema or outputSchema uses $ref to point to external or shared definitions, it is currently ambiguous how the hash is calculated.

If we hash the string literal {"$ref": "#/defs/Location"}, the hash becomes decoupled from the actual underlying schema logic. If the underlying definition changes, the hash stays the same.

Proposal: We need to specify whether implementations MUST fully resolve/bundle $ref pointers before canonicalization and hashing.

3. Discovery Speed vs. Transport Bloat (CEP-35)

Open architectural question:
I was considering if we could use the new CEP-35 stateless discovery tags to let servers advertise their schemaHash values in the first-message exchange. This would allow clients to discover common tools instantly without needing an extra tools/list RPC call.

However, as discussed, this crosses the boundary between transport capabilities (CEP-35) and application state (tools/list). It could also severely bloat the session envelope if a server implements many tools. Documenting this here to confirm that keeping tool hashes strictly attached to the tools/list response is the preferred path.

…anded field exclusions

Adds hash payload boundary definition, requires self-contained schema representation for $ref, expands normalization to exclude examples, default, deprecated, readOnly, writeOnly, and x-* vendor fields. Updates client conformance verification steps and implementation guidance.
@ContextVM-org
Copy link
Copy Markdown
Contributor Author

Thanks for the review. We updated the draft to address these edge cases.

  • Non-functional fields: the hash boundary is now explicit: only name, normalized inputSchema, and normalized outputSchema participate in the hash. Within schemas, CEP-15 now strips defined annotation/metadata fields and x-* vendor extensions before canonicalization.
  • $ref handling: the spec now requires hashing a self-contained schema representation rather than unresolved $ref strings, and it forbids live remote resolution during hash calculation.
  • Discovery scope: we kept schema-hash discovery on the existing CEP-15 surfaces rather than moving it into CEP-35. The draft now clarifies that direct ContextVM tools/list responses and CEP-6 tools announcements reuse the same underlying payload, so common-schema references should be carried consistently across both, including event-level i / k tags.

Let me know what do you think @abhayguptas

@abhayguptas
Copy link
Copy Markdown

Thanks for the quick update! I just pulled and reviewed the commit. The expanded normalization rules (stripping examples, default, x-*, etc.) and the self-contained $ref requirement look perfect and completely solve the edge cases.

I also really like the approach for discovery. Attaching the i and k tags directly to the tools/list response event is a great middle-ground—it keeps the CEP-35 transport layer clean from bloat while still giving clients fast event-level discovery. This looks rock solid to me! 🙂

@ContextVM-org
Copy link
Copy Markdown
Contributor Author

Great! Would you like to update your pr with this changes covering the edge cases so we can move forward?

@abhayguptas
Copy link
Copy Markdown

Hey! I've updated the PRs based on our recent review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants