setlist-mcp 0.1.0 → 0.3.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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "MCP server for setlist.fm — concert setlists, artists, venues, and tours via the setlist.fm API",
10
- "version": "0.1.0"
10
+ "version": "0.3.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "setlist.fm",
16
16
  "source": "./",
17
17
  "description": "MCP server for setlist.fm — search concert setlists, artists, venues, and tours via natural language",
18
- "version": "0.1.0",
18
+ "version": "0.3.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "setlist-mcp",
3
3
  "displayName": "setlist.fm",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "description": "MCP server for setlist.fm — search concert setlists, artists, venues, and tours via the setlist.fm API",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/README.md CHANGED
@@ -42,6 +42,15 @@ Optional: `SETLIST_ACCEPT_LANGUAGE` (one of `en, es, fr, de, pt, tr, it, pl`) lo
42
42
 
43
43
  See [SKILL.md](SKILL.md) for from-source setup, the full tool reference, and example flows.
44
44
 
45
+ ## Attribution & terms
46
+
47
+ Use is governed by the [setlist.fm API terms](https://www.setlist.fm/help/api-terms). In short:
48
+
49
+ - **Attribute setlist.fm.** Every result carries a `url`; surface it as a *followable* source link (no `nofollow`) wherever the data is shown. The tool descriptions instruct the model to do this, and results pass the `url` through verbatim.
50
+ - **Non-commercial only** under a free key — commercial use requires setlist.fm's permission.
51
+ - **No persistent caching** — this server makes a live API call per tool invocation and keeps no datastore. Please don't add one.
52
+ - **Keep your API key private** — it lives in `SETLIST_API_KEY` (`.env` is gitignored) and never appears in tool output.
53
+
45
54
  ## Development
46
55
 
47
56
  ```bash
package/SKILL.md CHANGED
@@ -100,6 +100,20 @@ All tools are read-only and prefixed `setlist_`.
100
100
  - **"Setlists at Red Rocks in 2023"** → `setlist_search_venues` (Red Rocks → venueId) → `setlist_search_setlists` with `venueId` + `year: 2023`.
101
101
  - **"Phish on 2023-08-07"** → `setlist_search_setlists` with `artistName: "Phish"`, `date: "07-08-2023"` (note the dd-MM-yyyy format).
102
102
 
103
+ ## Attribution & API terms
104
+
105
+ setlist.fm's [API terms](https://www.setlist.fm/help/api-terms) bind anyone using this data. When you present setlist.fm results to a user:
106
+
107
+ - **Always cite the source.** Each setlist/artist/venue result includes a `url` — show it as a real, clickable link to setlist.fm (e.g. "Source: [The Beatles setlist on setlist.fm](https://www.setlist.fm/...)"). The terms require a *followable* link — never a `nofollow`. If a particular result has no `url`, link to https://www.setlist.fm instead.
108
+ - **Non-commercial use only.** A free API key covers non-commercial use; commercial use needs setlist.fm's permission.
109
+ - **Live data, not a datastore.** The terms forbid persistent caching — this server fetches fresh on every call and you should treat results as point-in-time, not build a local copy.
110
+ - **Don't expose or share the API key.** It's read from `SETLIST_API_KEY` and never appears in results.
111
+
112
+ ## Interpreting setlist data
113
+
114
+ - Songs live in `sets.set[]`; each set may have an `encore` number (1 = first encore) and a `name` (e.g. an acoustic set or a full album).
115
+ - Each `song` may carry: `tape: true` (a pre-recorded intro/outro — not actually performed live), `cover` (the original artist when it's a cover), `with` (a guest performer), and `info` (a note like "acoustic" or "first time live"). Surface these when relevant rather than dropping them.
116
+
103
117
  ## Notes
104
118
 
105
119
  - IDs chain: `search_*` tools return the `mbid` / `setlistId` / `venueId` / `geoId` you feed into the `get_*` tools.
@@ -0,0 +1,6 @@
1
+ // setlist.fm API terms require a *followable* attribution link wherever their
2
+ // data appears (no nofollow): https://www.setlist.fm/help/api-terms. Every
3
+ // setlist/artist/venue object carries a `url` (passed through verbatim by
4
+ // textResult), so this note — appended to each data tool's description, but not
5
+ // to setlist_healthcheck — tells the model to surface that `url` as a source link.
6
+ export const ATTRIBUTION_NOTE = ' Results include a setlist.fm `url`; when you present this data, cite it as a clickable source link to setlist.fm (their API terms require followable attribution — no nofollow). If a result has no `url`, link to https://www.setlist.fm instead.';
package/dist/bundle.js CHANGED
@@ -31197,7 +31197,7 @@ function toolAnnotations(opts = {}) {
31197
31197
  }
31198
31198
 
31199
31199
  // src/version.ts
31200
- var VERSION = "0.1.0";
31200
+ var VERSION = "0.3.0";
31201
31201
 
31202
31202
  // src/client.ts
31203
31203
  import { dirname, join } from "path";
@@ -31252,13 +31252,16 @@ var SetlistClient = class {
31252
31252
  };
31253
31253
  var client = new SetlistClient();
31254
31254
 
31255
+ // src/attribution.ts
31256
+ var ATTRIBUTION_NOTE = " Results include a setlist.fm `url`; when you present this data, cite it as a clickable source link to setlist.fm (their API terms require followable attribution \u2014 no nofollow). If a result has no `url`, link to https://www.setlist.fm instead.";
31257
+
31255
31258
  // src/tools/artists.ts
31256
31259
  var page = external_exports.number().int().positive().optional().describe("Result page number (defaults to 1)");
31257
31260
  function registerArtistTools(server) {
31258
31261
  server.registerTool(
31259
31262
  "setlist_search_artists",
31260
31263
  {
31261
- description: "Search setlist.fm for artists by name or MusicBrainz ID. Returns matching artists with their MusicBrainz ID (mbid) \u2014 use that mbid with setlist_get_artist or setlist_get_artist_setlists.",
31264
+ description: "Search setlist.fm for artists by name or MusicBrainz ID. Returns matching artists with their MusicBrainz ID (mbid) \u2014 use that mbid with setlist_get_artist or setlist_get_artist_setlists." + ATTRIBUTION_NOTE,
31262
31265
  annotations: { readOnlyHint: true },
31263
31266
  inputSchema: {
31264
31267
  artistName: external_exports.string().optional().describe("Artist name to search for"),
@@ -31277,7 +31280,7 @@ function registerArtistTools(server) {
31277
31280
  server.registerTool(
31278
31281
  "setlist_get_artist",
31279
31282
  {
31280
- description: "Get a setlist.fm artist by their MusicBrainz ID (mbid).",
31283
+ description: "Get a setlist.fm artist by their MusicBrainz ID (mbid)." + ATTRIBUTION_NOTE,
31281
31284
  annotations: { readOnlyHint: true },
31282
31285
  inputSchema: {
31283
31286
  mbid: external_exports.string().describe("Artist's MusicBrainz ID (mbid)")
@@ -31291,7 +31294,7 @@ function registerArtistTools(server) {
31291
31294
  server.registerTool(
31292
31295
  "setlist_get_artist_setlists",
31293
31296
  {
31294
- description: "Get an artist's setlists (most recent first) by their MusicBrainz ID (mbid). Paginated via `p`.",
31297
+ description: "Get an artist's setlists (most recent first) by their MusicBrainz ID (mbid). Paginated via `p`." + ATTRIBUTION_NOTE,
31295
31298
  annotations: { readOnlyHint: true },
31296
31299
  inputSchema: {
31297
31300
  mbid: external_exports.string().describe("Artist's MusicBrainz ID (mbid)"),
@@ -31310,12 +31313,13 @@ function registerArtistTools(server) {
31310
31313
  }
31311
31314
 
31312
31315
  // src/tools/setlists.ts
31316
+ var SETLIST_SHAPE_NOTE = ' A setlist\'s songs live in `sets.set[]`; each set may have an `encore` number (1 = first encore) and a `name` (e.g. an acoustic set or a full album). Each `song` may carry: `tape: true` (pre-recorded intro/outro/interlude \u2014 not actually performed), `cover` (the original artist when it is a cover), `with` (a guest performer), and `info` (a note like "acoustic" or "first time live").';
31313
31317
  var page2 = external_exports.number().int().positive().optional().describe("Result page number (defaults to 1)");
31314
31318
  function registerSetlistTools(server) {
31315
31319
  server.registerTool(
31316
31320
  "setlist_search_setlists",
31317
31321
  {
31318
- description: "Search setlist.fm for concert setlists. Filter by any combination of artist, venue, city, country, tour, date, or year. Returns setlists with their songs and event details. Provide at least one filter.",
31322
+ description: "Search setlist.fm for concert setlists. Filter by any combination of artist, venue, city, country, tour, date, or year. Returns setlists with their songs and event details. Provide at least one filter." + ATTRIBUTION_NOTE,
31319
31323
  annotations: { readOnlyHint: true },
31320
31324
  inputSchema: {
31321
31325
  artistName: external_exports.string().optional().describe("Artist name"),
@@ -31342,7 +31346,7 @@ function registerSetlistTools(server) {
31342
31346
  server.registerTool(
31343
31347
  "setlist_get_setlist",
31344
31348
  {
31345
- description: "Get a setlist.fm setlist by its ID, including the full song list and event details.",
31349
+ description: "Get a setlist.fm setlist by its ID, including the full song list and event details." + SETLIST_SHAPE_NOTE + ATTRIBUTION_NOTE,
31346
31350
  annotations: { readOnlyHint: true },
31347
31351
  inputSchema: {
31348
31352
  setlistId: external_exports.string().describe("Setlist ID (e.g. 63de4613)")
@@ -31356,7 +31360,7 @@ function registerSetlistTools(server) {
31356
31360
  server.registerTool(
31357
31361
  "setlist_get_setlist_version",
31358
31362
  {
31359
- description: "Get a specific historical version of a setlist by its version ID. Setlists are wiki-edited; each edit has a version ID returned in a setlist's `versionId` field.",
31363
+ description: "Get a specific historical version of a setlist by its version ID. Setlists are wiki-edited; each edit has a version ID returned in a setlist's `versionId` field." + SETLIST_SHAPE_NOTE + ATTRIBUTION_NOTE,
31360
31364
  annotations: { readOnlyHint: true },
31361
31365
  inputSchema: {
31362
31366
  versionId: external_exports.string().describe("Setlist version ID")
@@ -31378,7 +31382,7 @@ function registerVenueTools(server) {
31378
31382
  server.registerTool(
31379
31383
  "setlist_search_venues",
31380
31384
  {
31381
- description: "Search setlist.fm for venues by name and/or location. Returns matching venues with their venue ID \u2014 use it with setlist_get_venue or setlist_get_venue_setlists.",
31385
+ description: "Search setlist.fm for venues by name and/or location. Returns matching venues with their venue ID \u2014 use it with setlist_get_venue or setlist_get_venue_setlists." + ATTRIBUTION_NOTE,
31382
31386
  annotations: { readOnlyHint: true },
31383
31387
  inputSchema: {
31384
31388
  name: external_exports.string().optional().describe("Venue name"),
@@ -31398,7 +31402,7 @@ function registerVenueTools(server) {
31398
31402
  server.registerTool(
31399
31403
  "setlist_get_venue",
31400
31404
  {
31401
- description: "Get a setlist.fm venue by its ID.",
31405
+ description: "Get a setlist.fm venue by its ID." + ATTRIBUTION_NOTE,
31402
31406
  annotations: { readOnlyHint: true },
31403
31407
  inputSchema: {
31404
31408
  venueId: external_exports.string().describe("Venue ID")
@@ -31412,7 +31416,7 @@ function registerVenueTools(server) {
31412
31416
  server.registerTool(
31413
31417
  "setlist_get_venue_setlists",
31414
31418
  {
31415
- description: "Get setlists performed at a venue, by venue ID (most recent first). Paginated via `p`.",
31419
+ description: "Get setlists performed at a venue, by venue ID (most recent first). Paginated via `p`." + ATTRIBUTION_NOTE,
31416
31420
  annotations: { readOnlyHint: true },
31417
31421
  inputSchema: {
31418
31422
  venueId: external_exports.string().describe("Venue ID"),
@@ -31436,7 +31440,7 @@ function registerGeoTools(server) {
31436
31440
  server.registerTool(
31437
31441
  "setlist_search_cities",
31438
31442
  {
31439
- description: "Search setlist.fm for cities by name and/or location. Returns cities with their geoId \u2014 use it as cityId in setlist_search_setlists / setlist_search_venues, or with setlist_get_city.",
31443
+ description: "Search setlist.fm for cities by name and/or location. Returns cities with their geoId \u2014 use it as cityId in setlist_search_setlists / setlist_search_venues, or with setlist_get_city." + ATTRIBUTION_NOTE,
31440
31444
  annotations: { readOnlyHint: true },
31441
31445
  inputSchema: {
31442
31446
  name: external_exports.string().optional().describe("City name"),
@@ -31454,7 +31458,7 @@ function registerGeoTools(server) {
31454
31458
  server.registerTool(
31455
31459
  "setlist_get_city",
31456
31460
  {
31457
- description: "Get a city by its geoId.",
31461
+ description: "Get a city by its geoId." + ATTRIBUTION_NOTE,
31458
31462
  annotations: { readOnlyHint: true },
31459
31463
  inputSchema: {
31460
31464
  geoId: external_exports.string().describe("City's geoId")
@@ -31468,7 +31472,7 @@ function registerGeoTools(server) {
31468
31472
  server.registerTool(
31469
31473
  "setlist_search_countries",
31470
31474
  {
31471
- description: "List all countries supported by setlist.fm, with their ISO country codes. Use a code as countryCode in setlist_search_setlists.",
31475
+ description: "List all countries supported by setlist.fm, with their ISO country codes. Use a code as countryCode in setlist_search_setlists." + ATTRIBUTION_NOTE,
31472
31476
  annotations: { readOnlyHint: true }
31473
31477
  },
31474
31478
  async () => {
@@ -31484,7 +31488,7 @@ function registerUserTools(server) {
31484
31488
  server.registerTool(
31485
31489
  "setlist_get_user",
31486
31490
  {
31487
- description: "Get a setlist.fm user's public profile by their userId (their setlist.fm username).",
31491
+ description: "Get a setlist.fm user's public profile by their userId (their setlist.fm username)." + ATTRIBUTION_NOTE,
31488
31492
  annotations: { readOnlyHint: true },
31489
31493
  inputSchema: {
31490
31494
  userId: external_exports.string().describe("setlist.fm userId (username)")
@@ -31498,7 +31502,7 @@ function registerUserTools(server) {
31498
31502
  server.registerTool(
31499
31503
  "setlist_get_user_attended",
31500
31504
  {
31501
- description: "Get the concerts a setlist.fm user has marked as attended. Paginated via `p`.",
31505
+ description: "Get the concerts a setlist.fm user has marked as attended. Paginated via `p`." + ATTRIBUTION_NOTE,
31502
31506
  annotations: { readOnlyHint: true },
31503
31507
  inputSchema: {
31504
31508
  userId: external_exports.string().describe("setlist.fm userId (username)"),
@@ -31517,7 +31521,7 @@ function registerUserTools(server) {
31517
31521
  server.registerTool(
31518
31522
  "setlist_get_user_edited",
31519
31523
  {
31520
- description: "Get the setlists a setlist.fm user has created or edited. Paginated via `p`.",
31524
+ description: "Get the setlists a setlist.fm user has created or edited. Paginated via `p`." + ATTRIBUTION_NOTE,
31521
31525
  annotations: { readOnlyHint: true },
31522
31526
  inputSchema: {
31523
31527
  userId: external_exports.string().describe("setlist.fm userId (username)"),
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { textResult } from '@chrischall/mcp-utils';
3
3
  import { client } from '../client.js';
4
+ import { ATTRIBUTION_NOTE } from '../attribution.js';
4
5
  const page = z
5
6
  .number()
6
7
  .int()
@@ -9,7 +10,8 @@ const page = z
9
10
  .describe('Result page number (defaults to 1)');
10
11
  export function registerArtistTools(server) {
11
12
  server.registerTool('setlist_search_artists', {
12
- description: "Search setlist.fm for artists by name or MusicBrainz ID. Returns matching artists with their MusicBrainz ID (mbid) — use that mbid with setlist_get_artist or setlist_get_artist_setlists.",
13
+ description: "Search setlist.fm for artists by name or MusicBrainz ID. Returns matching artists with their MusicBrainz ID (mbid) — use that mbid with setlist_get_artist or setlist_get_artist_setlists." +
14
+ ATTRIBUTION_NOTE,
13
15
  annotations: { readOnlyHint: true },
14
16
  inputSchema: {
15
17
  artistName: z.string().optional().describe('Artist name to search for'),
@@ -27,7 +29,7 @@ export function registerArtistTools(server) {
27
29
  return textResult(data);
28
30
  });
29
31
  server.registerTool('setlist_get_artist', {
30
- description: "Get a setlist.fm artist by their MusicBrainz ID (mbid).",
32
+ description: "Get a setlist.fm artist by their MusicBrainz ID (mbid)." + ATTRIBUTION_NOTE,
31
33
  annotations: { readOnlyHint: true },
32
34
  inputSchema: {
33
35
  mbid: z.string().describe("Artist's MusicBrainz ID (mbid)"),
@@ -37,7 +39,8 @@ export function registerArtistTools(server) {
37
39
  return textResult(data);
38
40
  });
39
41
  server.registerTool('setlist_get_artist_setlists', {
40
- description: "Get an artist's setlists (most recent first) by their MusicBrainz ID (mbid). Paginated via `p`.",
42
+ description: "Get an artist's setlists (most recent first) by their MusicBrainz ID (mbid). Paginated via `p`." +
43
+ ATTRIBUTION_NOTE,
41
44
  annotations: { readOnlyHint: true },
42
45
  inputSchema: {
43
46
  mbid: z.string().describe("Artist's MusicBrainz ID (mbid)"),
package/dist/tools/geo.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { textResult } from '@chrischall/mcp-utils';
3
3
  import { client } from '../client.js';
4
+ import { ATTRIBUTION_NOTE } from '../attribution.js';
4
5
  const page = z
5
6
  .number()
6
7
  .int()
@@ -9,7 +10,8 @@ const page = z
9
10
  .describe('Result page number (defaults to 1)');
10
11
  export function registerGeoTools(server) {
11
12
  server.registerTool('setlist_search_cities', {
12
- description: "Search setlist.fm for cities by name and/or location. Returns cities with their geoId — use it as cityId in setlist_search_setlists / setlist_search_venues, or with setlist_get_city.",
13
+ description: "Search setlist.fm for cities by name and/or location. Returns cities with their geoId — use it as cityId in setlist_search_setlists / setlist_search_venues, or with setlist_get_city." +
14
+ ATTRIBUTION_NOTE,
13
15
  annotations: { readOnlyHint: true },
14
16
  inputSchema: {
15
17
  name: z.string().optional().describe('City name'),
@@ -23,7 +25,7 @@ export function registerGeoTools(server) {
23
25
  return textResult(data);
24
26
  });
25
27
  server.registerTool('setlist_get_city', {
26
- description: "Get a city by its geoId.",
28
+ description: "Get a city by its geoId." + ATTRIBUTION_NOTE,
27
29
  annotations: { readOnlyHint: true },
28
30
  inputSchema: {
29
31
  geoId: z.string().describe("City's geoId"),
@@ -33,7 +35,8 @@ export function registerGeoTools(server) {
33
35
  return textResult(data);
34
36
  });
35
37
  server.registerTool('setlist_search_countries', {
36
- description: "List all countries supported by setlist.fm, with their ISO country codes. Use a code as countryCode in setlist_search_setlists.",
38
+ description: "List all countries supported by setlist.fm, with their ISO country codes. Use a code as countryCode in setlist_search_setlists." +
39
+ ATTRIBUTION_NOTE,
37
40
  annotations: { readOnlyHint: true },
38
41
  }, async () => {
39
42
  const data = await client.request('GET', '/1.0/search/countries');
@@ -1,6 +1,10 @@
1
1
  import { z } from 'zod';
2
2
  import { textResult } from '@chrischall/mcp-utils';
3
3
  import { client } from '../client.js';
4
+ import { ATTRIBUTION_NOTE } from '../attribution.js';
5
+ // How to read a setlist's song data (per setlist.fm's guidelines), so the model
6
+ // renders shows correctly. Appended to the get_setlist descriptions.
7
+ const SETLIST_SHAPE_NOTE = ' A setlist\'s songs live in `sets.set[]`; each set may have an `encore` number (1 = first encore) and a `name` (e.g. an acoustic set or a full album). Each `song` may carry: `tape: true` (pre-recorded intro/outro/interlude — not actually performed), `cover` (the original artist when it is a cover), `with` (a guest performer), and `info` (a note like "acoustic" or "first time live").';
4
8
  const page = z
5
9
  .number()
6
10
  .int()
@@ -9,7 +13,8 @@ const page = z
9
13
  .describe('Result page number (defaults to 1)');
10
14
  export function registerSetlistTools(server) {
11
15
  server.registerTool('setlist_search_setlists', {
12
- description: "Search setlist.fm for concert setlists. Filter by any combination of artist, venue, city, country, tour, date, or year. Returns setlists with their songs and event details. Provide at least one filter.",
16
+ description: "Search setlist.fm for concert setlists. Filter by any combination of artist, venue, city, country, tour, date, or year. Returns setlists with their songs and event details. Provide at least one filter." +
17
+ ATTRIBUTION_NOTE,
13
18
  annotations: { readOnlyHint: true },
14
19
  inputSchema: {
15
20
  artistName: z.string().optional().describe('Artist name'),
@@ -35,7 +40,9 @@ export function registerSetlistTools(server) {
35
40
  return textResult(data);
36
41
  });
37
42
  server.registerTool('setlist_get_setlist', {
38
- description: "Get a setlist.fm setlist by its ID, including the full song list and event details.",
43
+ description: "Get a setlist.fm setlist by its ID, including the full song list and event details." +
44
+ SETLIST_SHAPE_NOTE +
45
+ ATTRIBUTION_NOTE,
39
46
  annotations: { readOnlyHint: true },
40
47
  inputSchema: {
41
48
  setlistId: z.string().describe('Setlist ID (e.g. 63de4613)'),
@@ -45,7 +52,9 @@ export function registerSetlistTools(server) {
45
52
  return textResult(data);
46
53
  });
47
54
  server.registerTool('setlist_get_setlist_version', {
48
- description: "Get a specific historical version of a setlist by its version ID. Setlists are wiki-edited; each edit has a version ID returned in a setlist's `versionId` field.",
55
+ description: "Get a specific historical version of a setlist by its version ID. Setlists are wiki-edited; each edit has a version ID returned in a setlist's `versionId` field." +
56
+ SETLIST_SHAPE_NOTE +
57
+ ATTRIBUTION_NOTE,
49
58
  annotations: { readOnlyHint: true },
50
59
  inputSchema: {
51
60
  versionId: z.string().describe('Setlist version ID'),
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { textResult } from '@chrischall/mcp-utils';
3
3
  import { client } from '../client.js';
4
+ import { ATTRIBUTION_NOTE } from '../attribution.js';
4
5
  const page = z
5
6
  .number()
6
7
  .int()
@@ -9,7 +10,8 @@ const page = z
9
10
  .describe('Result page number (defaults to 1)');
10
11
  export function registerUserTools(server) {
11
12
  server.registerTool('setlist_get_user', {
12
- description: "Get a setlist.fm user's public profile by their userId (their setlist.fm username).",
13
+ description: "Get a setlist.fm user's public profile by their userId (their setlist.fm username)." +
14
+ ATTRIBUTION_NOTE,
13
15
  annotations: { readOnlyHint: true },
14
16
  inputSchema: {
15
17
  userId: z.string().describe('setlist.fm userId (username)'),
@@ -19,7 +21,8 @@ export function registerUserTools(server) {
19
21
  return textResult(data);
20
22
  });
21
23
  server.registerTool('setlist_get_user_attended', {
22
- description: "Get the concerts a setlist.fm user has marked as attended. Paginated via `p`.",
24
+ description: "Get the concerts a setlist.fm user has marked as attended. Paginated via `p`." +
25
+ ATTRIBUTION_NOTE,
23
26
  annotations: { readOnlyHint: true },
24
27
  inputSchema: {
25
28
  userId: z.string().describe('setlist.fm userId (username)'),
@@ -30,7 +33,8 @@ export function registerUserTools(server) {
30
33
  return textResult(data);
31
34
  });
32
35
  server.registerTool('setlist_get_user_edited', {
33
- description: "Get the setlists a setlist.fm user has created or edited. Paginated via `p`.",
36
+ description: "Get the setlists a setlist.fm user has created or edited. Paginated via `p`." +
37
+ ATTRIBUTION_NOTE,
34
38
  annotations: { readOnlyHint: true },
35
39
  inputSchema: {
36
40
  userId: z.string().describe('setlist.fm userId (username)'),
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { textResult } from '@chrischall/mcp-utils';
3
3
  import { client } from '../client.js';
4
+ import { ATTRIBUTION_NOTE } from '../attribution.js';
4
5
  const page = z
5
6
  .number()
6
7
  .int()
@@ -9,7 +10,8 @@ const page = z
9
10
  .describe('Result page number (defaults to 1)');
10
11
  export function registerVenueTools(server) {
11
12
  server.registerTool('setlist_search_venues', {
12
- description: "Search setlist.fm for venues by name and/or location. Returns matching venues with their venue ID — use it with setlist_get_venue or setlist_get_venue_setlists.",
13
+ description: "Search setlist.fm for venues by name and/or location. Returns matching venues with their venue ID — use it with setlist_get_venue or setlist_get_venue_setlists." +
14
+ ATTRIBUTION_NOTE,
13
15
  annotations: { readOnlyHint: true },
14
16
  inputSchema: {
15
17
  name: z.string().optional().describe('Venue name'),
@@ -25,7 +27,7 @@ export function registerVenueTools(server) {
25
27
  return textResult(data);
26
28
  });
27
29
  server.registerTool('setlist_get_venue', {
28
- description: "Get a setlist.fm venue by its ID.",
30
+ description: "Get a setlist.fm venue by its ID." + ATTRIBUTION_NOTE,
29
31
  annotations: { readOnlyHint: true },
30
32
  inputSchema: {
31
33
  venueId: z.string().describe('Venue ID'),
@@ -35,7 +37,8 @@ export function registerVenueTools(server) {
35
37
  return textResult(data);
36
38
  });
37
39
  server.registerTool('setlist_get_venue_setlists', {
38
- description: "Get setlists performed at a venue, by venue ID (most recent first). Paginated via `p`.",
40
+ description: "Get setlists performed at a venue, by venue ID (most recent first). Paginated via `p`." +
41
+ ATTRIBUTION_NOTE,
39
42
  annotations: { readOnlyHint: true },
40
43
  inputSchema: {
41
44
  venueId: z.string().describe('Venue ID'),
package/dist/version.js CHANGED
@@ -3,4 +3,4 @@
3
3
  // release-please-config.json's `extra-files`), and `versionSyncTest` guards
4
4
  // that it stays equal to package.json. Import VERSION wherever the version is
5
5
  // needed rather than re-declaring it.
6
- export const VERSION = '0.1.0'; // x-release-please-version
6
+ export const VERSION = '0.3.0'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "setlist-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "mcpName": "io.github.chrischall/setlist-mcp",
5
5
  "description": "setlist.fm MCP server for Claude — developed and maintained by AI (Claude Code)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/chrischall/setlist-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.1.0",
9
+ "version": "0.3.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "setlist-mcp",
14
- "version": "0.1.0",
14
+ "version": "0.3.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },