Compare commits

..

1 Commits

Author SHA1 Message Date
pablof7z
72f63c9e3b Add NIP-AD: MCP Server and Skill Announcements 2026-02-12 22:54:58 +00:00
6 changed files with 273 additions and 190 deletions

257
11.md
View File

@@ -6,7 +6,7 @@ Relay Information Document
`draft` `optional` `relay`
Relays may provide server metadata to clients to inform them of capabilities, administrative contacts, and various server attributes. This is made available as a JSON document over HTTP, on the same URI as the relay's websocket.
Relays may provide server metadata to clients to inform them of capabilities, administrative contacts, and various server attributes. This is made available as a JSON document over HTTP, on the same URI as the relay's websocket.
When a relay receives an HTTP(s) request with an `Accept` header of `application/nostr+json` to a URI supporting WebSocket upgrades, they SHOULD return a document with the following structure.
@@ -22,7 +22,8 @@ When a relay receives an HTTP(s) request with an `Accept` header of `application
"supported_nips": <a list of NIP numbers supported by the relay>,
"software": <string identifying relay software URL>,
"version": <string version identifier>,
"terms_of_service": <a link to a text file describing the relay's term of service>
"privacy_policy": <a link to a text file describing the relay's privacy policy>,
"terms_of_service": <a link to a text file describing the relay's term of service>,
}
```
@@ -33,11 +34,11 @@ Field Descriptions
### Name
A relay may select a `name` for use in client software. This is a string, and SHOULD be less than 30 characters to avoid client truncation.
A relay may select a `name` for use in client software. This is a string, and SHOULD be less than 30 characters to avoid client truncation.
### Description
Detailed plain-text information about the relay may be contained in the `description` string. It is recommended that this contain no markup, formatting or line breaks for word wrapping, and simply use double newline characters to separate paragraphs. There are no limitations on length.
Detailed plain-text information about the relay may be contained in the `description` string. It is recommended that this contain no markup, formatting or line breaks for word wrapping, and simply use double newline characters to separate paragraphs. There are no limitations on length.
### Banner
@@ -56,7 +57,7 @@ Icon is a compact visual representation of the relay for use in UI with limited
### Pubkey
An administrative contact may be listed with a `pubkey`, in the same format as Nostr events (32-byte hex for a `secp256k1` public key). If a contact is listed, this provides clients with a recommended address to send encrypted direct messages (See [NIP-17](17.md)) to a system administrator. Expected uses of this address are to report abuse or illegal content, file bug reports, or request other technical assistance.
An administrative contact may be listed with a `pubkey`, in the same format as Nostr events (32-byte hex for a `secp256k1` public key). If a contact is listed, this provides clients with a recommended address to send encrypted direct messages (See [NIP-17](17.md)) to a system administrator. Expected uses of this address are to report abuse or illegal content, file bug reports, or request other technical assistance.
Relay operators have no obligation to respond to direct messages.
@@ -66,23 +67,29 @@ A relay MAY maintain an identity independent from its administrator using the `s
### Contact
An alternative contact may be listed under the `contact` field as well, with the same purpose as `pubkey`. Use of a Nostr public key and direct message SHOULD be preferred over this. Contents of this field SHOULD be a URI, using schemes such as `mailto` or `https` to provide users with a means of contact.
An alternative contact may be listed under the `contact` field as well, with the same purpose as `pubkey`. Use of a Nostr public key and direct message SHOULD be preferred over this. Contents of this field SHOULD be a URI, using schemes such as `mailto` or `https` to provide users with a means of contact.
### Supported NIPs
As the Nostr protocol evolves, some functionality may only be available by relays that implement a specific `NIP`. This field is an array of the integer identifiers of `NIP`s that are implemented in the relay. Examples would include `1`, for `"NIP-01"` and `9`, for `"NIP-09"`. Client-side `NIPs` SHOULD NOT be advertised, and can be ignored by clients.
As the Nostr protocol evolves, some functionality may only be available by relays that implement a specific `NIP`. This field is an array of the integer identifiers of `NIP`s that are implemented in the relay. Examples would include `1`, for `"NIP-01"` and `9`, for `"NIP-09"`. Client-side `NIPs` SHOULD NOT be advertised, and can be ignored by clients.
### Software
The relay server implementation MAY be provided in the `software` attribute. If present, this MUST be a URL to the project's homepage.
The relay server implementation MAY be provided in the `software` attribute. If present, this MUST be a URL to the project's homepage.
### Version
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
### Privacy Policy
The relay owner/admin MAY choose to link to a privacy policy document, which describes how the relay utilizes user data. Data collection, data usage, data retention, monetization of data, and third party data sharing SHOULD be included.
### Terms of Service
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
The relay owner/admin MAY choose to link to a terms of service document.
Extra Fields
------------
@@ -160,6 +167,112 @@ a specific niche kind or content. Normal anti-spam heuristics, for example, do n
- `default_limit`: The maximum returned events if you send a filter without a `limit`.
### Event Retention
There may be a cost associated with storing data forever, so relays
may wish to state retention times. The values stated here are defaults
for unauthenticated users and visitors. Paid users would likely have
other policies.
Retention times are given in seconds, with `null` indicating infinity.
If zero is provided, this means the event will not be stored at
all, and preferably an error will be provided when those are received.
```jsonc
{
"retention": [
{"kinds": [0, 1, [5, 7], [40, 49]], "time": 3600},
{"kinds": [[40000, 49999]], "time": 100},
{"kinds": [[30000, 39999]], "count": 1000},
{"time": 3600, "count": 10000}
],
// other fields...
}
```
`retention` is a list of specifications: each will apply to either all kinds, or
a subset of kinds. Ranges may be specified for the kind field as a tuple of inclusive
start and end values. Events of indicated kind (or all) are then limited to a `count`
and/or time period.
It is possible to effectively blacklist Nostr-based protocols that rely on
a specific `kind` number, by giving a retention time of zero for those `kind` values.
While that is unfortunate, it does allow clients to discover servers that will
support their protocol quickly via a single HTTP fetch.
There is no need to specify retention times for _ephemeral events_ since they are not retained.
### Content Limitations
Some relays may be governed by the arbitrary laws of a nation state. This
may limit what content can be stored in clear-text on those relays. All
clients are encouraged to use encryption to work around this limitation.
It is not possible to describe the limitations of each country's laws
and policies which themselves are typically vague and constantly shifting.
Therefore, this field allows the relay operator to indicate which
countries' laws might end up being enforced on them, and then
indirectly on their users' content.
Users should be able to avoid relays in countries they don't like,
and/or select relays in more favorable zones. Exposing this
flexibility is up to the client software.
```jsonc
{
"relay_countries": [ "CA", "US" ],
// other fields...
}
```
- `relay_countries`: a list of two-level ISO country codes (ISO 3166-1 alpha-2) whose
laws and policies may affect this relay. `EU` may be used for European Union countries. A `*` can be used for global relays.
Remember that a relay may be hosted in a country which is not the
country of the legal entities who own the relay, so it's very
likely a number of countries are involved.
### Community Preferences
For public text notes at least, a relay may try to foster a
local community. This would encourage users to follow the global
feed on that relay, in addition to their usual individual follows.
To support this goal, relays MAY specify some of the following values.
```jsonc
{
"language_tags": ["en", "en-419"],
"tags": ["sfw-only", "bitcoin-only", "anime"],
"posting_policy": "https://example.com/posting-policy.html",
// other fields...
}
```
- `language_tags` is an ordered list
of [IETF language tags](https://en.wikipedia.org/wiki/IETF_language_tag) indicating
the major languages spoken on the relay. A `*` can be used for global relays.
- `tags` is a list of limitations on the topics to be discussed.
For example `sfw-only` indicates that only "Safe For Work" content
is encouraged on this relay. This relies on assumptions of what the
"work" "community" feels "safe" talking about. In time, a common
set of tags may emerge that allow users to find relays that suit
their needs, and client software will be able to parse these tags easily.
The `bitcoin-only` tag indicates that any *altcoin*, *"crypto"* or *blockchain*
comments will be ridiculed without mercy.
- `posting_policy` is a link to a human-readable page which specifies the
community policies for the relay. In cases where `sfw-only` is True, it's
important to link to a page which gets into the specifics of your posting policy.
The `description` field should be used to describe your community
goals and values, in brief. The `posting_policy` is for additional
detail and legal terms. Use the `tags` field to signify limitations
on content, or topics to be discussed, which could be machine
processed by appropriate client software.
### Pay-to-Relay
Relays that require payments may want to expose their fee schedules.
@@ -178,68 +291,82 @@ Relays that require payments may want to expose their fee schedules.
### Examples
```yaml
~> curl -H "Accept: application/nostr+json" https://nostr.wine | jq
{
"contact": "wino@nostr.wine",
"description": "A paid nostr relay for wine enthusiasts and everyone else.",
"fees": {
"admission": [
{
"amount": 18888000,
"unit": "msats"
}
]
},
"icon": "https://image.nostr.build/30acdce4a81926f386622a07343228ae99fa68d012d54c538c0b2129dffe400c.png",
"limitation": {
"auth_required": false,
"created_at_lower_limit": 94608000,
"created_at_upper_limit": 300,
"max_event_tags": 4000,
"max_limit": 1000,
"max_message_length": 524288,
"max_subid_length": 71,
"max_subscriptions": 50,
"min_pow_difficulty": 0,
"payment_required": true,
"restricted_writes": true
},
"name": "nostr.wine",
"payments_url": "https://nostr.wine/invoices",
"pubkey": "4918eb332a41b71ba9a74b1dc64276cfff592e55107b93baae38af3520e55975",
"software": "https://nostr.wine",
"supported_nips": [ 1, 2, 4, 9, 11, 40, 42, 50, 70, 77 ],
"terms_of_service": "https://nostr.wine/terms",
"version": "0.3.3"
}
As of 25 March 2025 the following command provided these results:
~> curl -H "Accept: application/nostr+json" https://nostr.land | jq
```bash
curl -H "Accept: application/nostr+json" https://jellyfish.land | jq
```
```json
{
"description": "[✨ NFDB] nostr.land family of relays (fi-01 [tiger])",
"name": "[✨ NFDB] nostr.land",
"pubkey": "52b4a076bcbbbdc3a1aefa3735816cf74993b1b8db202b01c883c58be7fad8bd",
"software": "NFDB",
"icon": "https://i.nostr.build/b3thno790aodH8lE.jpg",
"supported_nips": [ 1, 2, 4, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 44, 46, 47, 48, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 65, 68, 69, 71, 72, 73, 75, 78, 84, 88, 89, 90, 92, 99 ],
"version": "1.0.0",
"limitation": {
"payment_required": true,
"max_message_length": 65535,
"max_event_tags": 2000,
"max_subscriptions": 200,
"auth_required": false
},
"payments_url": "https://nostr.land",
"name": "JellyFish",
"description": "Stay Immortal!",
"banner": "https://image.nostr.build/7fdefea2dec1f1ec25b8ce69362566c13b2b7f13f1726c2e4584f05f64f62496.jpg",
"pubkey": "bf2bee5281149c7c350f5d12ae32f514c7864ff10805182f4178538c2c421007",
"contact": "hi@dezh.tech",
"software": "https://github.com/dezh-tech/immortal",
"supported_nips": [
1,
9,
11,
13,
17,
40,
42,
59,
62,
70
],
"version": "immortal - 0.0.9",
"relay_countries": [
"*"
],
"language_tags": [
"*"
],
"tags": [],
"posting_policy": "https://jellyfish.land/tos.txt",
"payments_url": "https://jellyfish.land/relay",
"icon": "https://image.nostr.build/2547e9ec4b23589e09bc7071e0806c3d4293f76284c58ff331a64bce978aaee8.jpg",
"retention": [],
"fees": {
"subscription": [
{
"amount": 4000000,
"unit": "msats",
"period": 2592000
"amount": 3000,
"period": 2628003,
"unit": "sats"
},
{
"amount": 8000,
"period": 7884009,
"unit": "sats"
},
{
"amount": 15000,
"period": 15768018,
"unit": "sats"
},
{
"amount": 28000,
"period": 31536036,
"unit": "sats"
}
]
},
"terms_of_service": "https://nostr.land/terms"
"limitation": {
"auth_required": false,
"max_message_length": 70000,
"max_subid_length": 256,
"max_subscriptions": 350,
"min_pow_difficulty": 0,
"payment_required": true,
"restricted_writes": true,
"max_event_tags": 2000,
"max_content_length": 70000,
"created_at_lower_limit": 0,
"created_at_upper_limit": 2147483647,
"default_limit": 500,
"max_limit": 5000
}
}
```

6
52.md
View File

@@ -95,7 +95,6 @@ Aside from the common tags, this also takes the following tags:
* `end` (optional) exclusive end Unix timestamp in seconds. If omitted, the calendar event ends instantaneously.
* `start_tzid` (optional) time zone of the start timestamp, as defined by the IANA Time Zone Database. e.g., `America/Costa_Rica`
* `end_tzid` (optional) time zone of the end timestamp, as defined by the IANA Time Zone Database. e.g., `America/Costa_Rica`. If omitted and `start_tzid` is provided, the time zone of the end timestamp is the same as the start timestamp.
* `D` (required) the day-granularity unix timestamp on which the event takes place, calculated as `floor(unix_seconds() / seconds_in_one_day)`. Multiple tags SHOULD be included to cover the event's timeframe.
```yaml
{
@@ -114,7 +113,6 @@ Aside from the common tags, this also takes the following tags:
// timestamps
["start", "<unix timestamp in seconds>"],
["end", "<unix timestamp in seconds>"],
["D", "82549"],
["start_tzid", "<IANA Time Zone Database identifier>"],
["end_tzid", "<IANA Time Zone Database identifier>"],
@@ -205,6 +203,10 @@ The list of tags is as follows:
}
```
## Unsolved Limitations
* No private events
## Intentionally Unsupported Scenarios
### Recurring Calendar Events

2
55.md
View File

@@ -249,7 +249,7 @@ launcher.launch(intent)
```kotlin
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$encryptedText"))
intent.`package` = "com.example.signer"
intent.putExtra("type", "nip44_decrypt")
intent.putExtra("type", "nip04_decrypt")
// to control the result in your application in case you are not waiting the result before sending another intent
intent.putExtra("id", "some_id")
// Send the current logged in user pubkey

73
AD.md Normal file
View File

@@ -0,0 +1,73 @@
NIP-AD
======
MCP Server and Skill Announcements
----------------------------------
`draft` `optional`
Defines event kinds for announcing MCP servers and skills.
---
## MCP Server Announcement (Kind 4200)
Announces an MCP server that provides tools to agents.
```json
{
"kind": 4200,
"pubkey": "<publisher-pubkey>",
"tags": [
["name", "<server-name>"],
["description", "<what-the-server-does>"],
["command", "<execution-command>"]
],
"content": ""
}
```
### Tags
- `name` — Server identifier
- `description` — What the server provides
- `command` — Command to start the server (e.g., `npx @anthropic-ai/mcp-server-fetch`)
---
## Skill Announcement (Kind 4202)
Announces a skill—packaged capabilities with instructions and associated files.
```json
{
"kind": 4202,
"pubkey": "<publisher-pubkey>",
"tags": [
["title", "<skill-name>"],
["description", "<what-the-skill-does>"],
["e", "<1063-event-id>"],
["license", "<SPDX-identifier>"]
],
"content": "<skill-instructions>"
}
```
### Tags
- `title` — Skill name
- `description` — One-line description
- `e` — Reference to NIP-94 file metadata (kind 1063), one or more
- `license` — SPDX license identifier
### Content
Contains skill instructions in markdown, injected into agent context when active.
### Referenced Files
Each `e` tag references a kind 1063 event with:
- `url` — File location
- `name` — Relative filepath for installation
- `m` — MIME type
- `x` — SHA-256 hash

119
C1.md
View File

@@ -1,119 +0,0 @@
NIP-C1
======
Collaborative Ownership
-----------------------
`draft` `optional`
This NIP defines a mechanism for multiple pubkeys to collaboratively maintain addressable events while preserving backwards compatibility.
## Motivation
Certain applications require shared ownership where:
1. **Attribution matters**: Each collaborator signs with their own key
2. **Dynamic membership**: Owners can be added or removed
3. **Backwards compatibility**: Non-supporting clients see normal events
## Specification
### Collaborative Pointer Event
A new addressable event kind `39382` serves as a pointer to collaboratively-owned content:
```jsonc
{
"kind": 39382,
"pubkey": "<creator-pubkey>",
"tags": [
["d", "<target-kind>-<slug>"],
["k", "<target-kind>"],
["p", "<owner-1-pubkey>"],
["p", "<owner-2-pubkey>"],
["p", "<owner-3-pubkey>"],
["relay", "wss://relay1.example.com"],
["relay", "wss://relay2.example.com"]
],
"content": "",
"created_at": 1234567890
}
```
#### Tag Definitions
| Tag | Required | Description |
|-----|----------|-------------|
| `d` | Yes | `<target-kind>-<slug>` - prevents collisions across kinds |
| `k` | Yes | Target event kind (avoids string parsing of `d` tag) |
| `p` | Yes | Owner pubkeys (one or more) |
| `relay` | No | Relay hints; if absent, use NIP-65 outbox model |
### Resolution Algorithm
To resolve the current state of collaboratively-owned content:
1. Parse the `39382` pointer event to extract owners (`p` tags) and target kind (`k` tag)
2. Extract the slug from the `d` tag (everything after the first `-`)
3. Query: `{"kinds": [<target-kind>], "authors": [<all-owners>], "#d": ["<slug>"], "limit": 1}`
4. Use `relay` tags if present; otherwise fall back to NIP-65 outbox relays
5. Return the event with the highest `created_at`
### Back-Reference (Optional)
Target events MAY include an `a` tag pointing to the `39382` pointer:
```jsonc
{
"kind": 30023,
"tags": [
["d", "my-article"],
["a", "39382:<pointer-creator-pubkey>:30023-my-article"]
]
}
```
This enables clients to discover that an event is part of a collaborative set.
## Example
### Pointer Event
```jsonc
{
"kind": 39382,
"pubkey": "alice-pubkey",
"tags": [
["d", "30023-collaborative-guide"],
["k", "30023"],
["p", "alice-pubkey"],
["p", "bob-pubkey"],
["p", "carol-pubkey"],
["relay", "wss://relay.example.com"]
],
"content": ""
}
```
### Target Article (by any owner)
```jsonc
{
"kind": 30023,
"pubkey": "bob-pubkey",
"tags": [
["d", "collaborative-guide"],
["title", "A Collaborative Guide"],
["a", "39382:alice-pubkey:30023-collaborative-guide"]
],
"content": "..."
}
```
### Client Resolution
1. Client receives `naddr` for the `39382` pointer
2. Parses owners: `[alice, bob, carol]`
3. Queries: `{"kinds": [30023], "authors": ["alice", "bob", "carol"], "#d": ["collaborative-guide"], "limit": 1}`
4. Returns most recent version regardless of which owner published it

View File

@@ -105,11 +105,11 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-99: Classified Listings](99.md)
- [NIP-A0: Voice Messages](A0.md)
- [NIP-A4: Public Messages](A4.md)
- [NIP-AD: MCP Server and Skill Announcements](AD.md)
- [NIP-B0: Web Bookmarks](B0.md)
- [NIP-B7: Blossom](B7.md)
- [NIP-BE: Nostr BLE Communications Protocol](BE.md)
- [NIP-C0: Code Snippets](C0.md)
- [NIP-C1: Collaborative Ownership](C1.md)
- [NIP-C7: Chats](C7.md)
- [NIP-EE: E2EE Messaging using MLS Protocol](EE.md) --- **unrecommended**: superseded by the [Marmot Protocol](https://github.com/marmot-protocol/marmot)
@@ -179,6 +179,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `2003` | Torrent | [35](35.md) |
| `2004` | Torrent Comment | [35](35.md) |
| `2022` | Coinjoin Pool | [joinstr][joinstr] |
| `4200` | MCP Server Announcement | [AD](AD.md) |
| `4202` | Skill Announcement | [AD](AD.md) |
| `4550` | Community Post Approval | [72](72.md) |
| `5000`-`5999` | Job Request | [90](90.md) |
| `6000`-`6999` | Job Result | [90](90.md) |
@@ -295,7 +297,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `39000-9` | Group metadata events | [29](29.md) |
| `39089` | Starter packs | [51](51.md) |
| `39092` | Media starter packs | [51](51.md) |
| `39382` | Collaborative Pointer | [C1](C1.md) |
| `39701` | Web bookmarks | [B0](B0.md) |
[NUD: Custom Feeds]: https://wikifreedia.xyz/cip-01/
@@ -350,7 +351,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `A` | root address | relay URL | [22](22.md) |
| `c` | commit id | | [34](34.md) |
| `d` | identifier | -- | [01](01.md) |
| `D` | day | -- | [52](52.md) |
| `e` | event id (hex) | relay URL, marker, pubkey (hex) | [01](01.md), [10](10.md) |
| `E` | root event id | relay URL | [22](22.md) |
| `f` | currency code | -- | [69](69.md) |