Visió general
Què és VISC, el model multi-tenant, l'estructura d'URLs i el full de ruta d'API i MCP.
Documentació perquè els agents d'IA entenguin VISC de pressa: com s'organitza la plataforma, quines dades hi viuen i com poden ajudar els seus usuaris a crear-hi contingut ric — avui, amb un sol text que l'usuari enganxa.
Els documents màquina són en anglès (el vocabulari de la plataforma es manté en català); el contingut que es crea a VISC és sempre en català. Aquesta pàgina en mostra exactament el mateix contingut.
Què és VISC, el model multi-tenant, l'estructura d'URLs i el full de ruta d'API i MCP.
Com qualsevol persona amb compte a VISC —sense ser administradora— connecta el seu propi assistent d'IA: passos per a Claude, què pot i què no pot fer, i on revocar-ho.
El manifest de conjunts de dades que ja es poden llegir en JSON des de la CDN, la seva frescor i les regles d'ús.
Com escriure un sol text markdown que un usuari enganxa per crear una pàgina rica sencera.
Tres escenaris complets, inclòs un prompt llest per copiar per a qualsevol assistent.
VISC (Vida, Informació, Serveis, Comunitat) is a multi-tenant platform where local communities — associations, neighbourhoods, cooperatives, local businesses — and the people around them organise daily life: agenda, news, payments, inscriptions, maps, tips and local commerce. It is rooted in Catalunya: all 947 municipalities are first-class pages, and the platform's content language is Catalan.
This document set exists so AI agents can understand VISC quickly and help its users well. Start here, then read the other docs listed in llms.txt.
Three kinds of "place" organise everything on VISC:
| URL | What it is |
|---|---|
| / · /atles | «L'Atles»: Catalunya in 3D relief, from the whole country down to a town's «Maqueta» (its buildings, trees, streets, real weather and sun). /inici is the classic landing |
| /3D | The 3D figures: festive figures (gegants, bestiari), heritage scans, landmarks |
| /catalunya | Territorial explore page (map, agenda, news) |
| /rutes · /transport | Hiking routes (GR, PR, SL and town routes) and the public-transport trip planner («Com hi arribo») |
| /publica | «Publica el teu acte»: anyone signed in sends an act to a town's agenda (moderated) |
| /agenda · /avisos · /comunitats · /receptes | Catalunya-wide agenda, hazard alerts, community directory and curated recipes. Each has a per-territory variant one segment down: /{comarcaSlug}/agenda, /{localitySlug}/receptes, … |
| /natura · /patrimoni · /fauna · /xifres · … | The 53 territorial subjects (discovery indexes, one subject each) — listed in Territorial subjects below |
| /catalunya/actualitat | Catalunya-wide news feed |
| /{comarcaSlug} | One of the 43 comarca landing pages |
| /{localitySlug} | A municipality's public page |
| /{localitySlug}/vida · /serveis · /comunitat | The municipality's pillar pages (see Localities above) |
| /{localitySlug}/informacio | The municipality's information page: civic incidences, the local information channel and the open municipal data sections — see The locality information page below |
| /{localitySlug}/{topicSlug} | A citizen-curated topic page (dossier) in that municipality |
| /{communitySlug} | A community's public showcase |
| /u/{username} | A person's public profile |
| /que | "Què és VISC" — the human About page |
| /com | How-to guides |
| /agents | The human-readable version of these docs |
Anything under /on/, /auth/, /org/ or /{slug}/admin is private and not crawlable.
A subject is a root discovery page answering "everything of one kind, across the territory": a true total, counts by type and by comarca, and a grid of cards. Every subject exists at four territory levels — /{subject} (Catalunya), /{comarcaSlug}/{subject}, /{vegueriaSlug}/{subject} and /{provinceSlug}/{subject} — and is server-rendered from one static file per subject and level, with zero database reads. /bolets and /llengua are the exceptions: Catalunya-wide only, with a page per item (/bolets/{slug}, /llengua/{slug}). The big geographic subjects show a curated selection beside true totals; the exhaustive list for one municipality is on its locality page or its information page, which is where each card links. Every subject's data is in the dataset manifest — prefer the JSON over scraping these pages.
The 53 subjects:
/bolets, /arbres and /llengua are Catalunya-wide only. The subject ids for get_subject are in the manifest (list_datasets → params.subjectID).
Every town's agenda is gathered from open data, not typed in: the Generalitat's Agenda Cultural, festes locals, the ajuntaments' own agendas (Barcelona, Tarragona, town-hall feeds), the Diputació de Barcelona's libraries, museums, parks and exhibitions, fairs, the OAC mobile offices, cinema en català, theatre, Festa Major programmes, and the acts people send with «Publica el teu acte» once a moderator approves them. The communities' own public events sit beside them. Ask get_upcoming_events with a localityCode (the town's whole agenda, plus acts nearby), a comarcaCode, or nothing (Catalonia, next 8 days); each event names its source and links its own page. Prefer that over scraping the agenda pages.
/atles is Catalunya in 3D: zoom from the whole country to a vegueria, a comarca, a town, and into its «Maqueta» — Cadastre buildings, real trees, streets with their furniture, rails and cable cars running their timetable, the forecast weather and the real sun and moon. A link can open it on any point: https://visc.cat/atles?at={lat},{lng}&d={metres} (inside Catalunya; d from 150 to 400,000, default 1,200). Send a person there when the answer is a place. The 3D files are for people, not crawlers: they are closed in robots.txt and counted against a daily download allowance in the browser.
/{localitySlug}/informacio (short aliases /{localitySlug}/i and /{localitySlug}/info) is a municipality's civic page. Besides the map of open incidences and the local information channel, it carries the town's open municipal data, one section per source, each hidden when the town has no data: drinking water, municipal finances, public services, the town in figures, jobs, housing, grants, connectivity, energy, waste, the recurring plenary subjects («Tòpics dels plens»), the municipal election result, how openly the ajuntament publishes («Com publica l'ajuntament») — plus weather, topics, citizen ratings of public services, paid parking and webcams. Each section is addressable with a fragment: #water, #finances, #serveis, #pulse, #feina, #habitatge, #subvencions, #connectivitat, #energia, #residus, #temes, #elections, #transparencia, #weather. The data behind each section is one static file per municipality, listed in the dataset manifest.
Catalan terms you will meet across the platform, kept untranslated on purpose:
Content pasted into VISC must be in Catalan and grounded in real, verifiable sources — see the grounding rules in the authoring contract.
VISC is free, and the civic part stays free for everyone, agents included: every public page and dataset, the agenda, alerts, services, transport, incidences, the public /mcp and the prepare_* links, and a person's own OAuth connection.
VISC+ («visc al límit») is the planned personal and group subscription — not available yet; nothing below can be bought or relied on today. What it is designed to add for a person and their assistant:
What money never buys, on VISC+ or anywhere: trust on the contribution ladder (more incidences or acts a day), ranking (no boost for a subscriber's content), or publication by an AI — an assistant prepares, a person publishes. Civic information, safety and transit are never behind it. When VISC+ opens, these docs will say so and list its scopes and limits.
Interest or feedback: use the Envia feedback button in the footer of any VISC page — it reaches the platform team directly.
You do not need to be an administrator of anything to use VISC from an AI assistant. Any person with a VISC account can connect their own assistant to their own account, and the connection is theirs alone: they grant it, they see what it did, they revoke it.
There are two levels, and the first one needs no setup at all.
Anonymous, public data. Point any MCP client at https://visc.cat/mcp — no account, no sign-in, no key. That gives access to everything VISC publishes: the 947 municipalities, their agendas, news, open civic incidences, topic pages, comarca profiles, the communities' public pages. It can also prepare things for you to add: an act for your town's agenda, an incidence, a recipe, an event for your community, a whole new community — it answers with a VISC link that opens the form already filled, and you send it yourself. If that is all you want, stop here; the rest of this page is not needed. See tools.md for what's available.
Your own account. Point it at https://visc.cat/mcp/me instead and it will ask you to sign in to VISC and approve the connection. Then your assistant can read your data — your communities, your inscriptions, your saved events — propose content you publish yourself, and, if you allow it, send acts to the agenda's moderation queue in your name. That is what this page is about.
You approve a specific set of permissions on a screen that names them in Catalan. What a person can grant today:
| Permission | What it allows |
|---|---|
| read:own | your public profile, your communities, your inscriptions, your saved agenda items |
| read:profile | your vincles (the towns you live, work, were born in, love or want to visit; the places you starred) and your plan profile (who comes with you, free time, activities, how you move) — so it can tell you what would make VISC work better for you and which communities fit |
| propose:profile | propose changes to those vincles and that profile. Nothing changes until you press «Aplica» on /on/pendents |
| read:community | a private summary of a community you belong to — its events, posts and poll results. Never a member list |
| propose:content | draft topic pages and entries for a municipality, or a new community, for you to review and publish (a community you publish is yours: you are its owner, the assistant never a member) |
| propose:incidence | draft a civic incidence report you described, for you to review and publish |
| submit:agenda | send an act to a town's agenda in your name: it goes to the same moderation queue as your own «Publica el teu acte», spends your daily limit for acts, and is public only once a moderator approves it. You follow it under «Els teus actes» on /publica |
| feedback | file a bug report or request with the VISC team |
What no connection can ever do, whatever you approve — there is no tool for it and no permission that expresses it:
Records you publish from an assistant's proposal are marked as agent-prepared. That is deliberate: readers can see how something was made.
The connector is now available from the + menu in any conversation.
claude mcp add --scope user --transport http visc https://visc.cat/mcp/meclaude mcp list will show visc as ! Needs authentication. Start a session, run /mcp, select visc, choose Authenticate, and approve in the browser that opens. Drop --scope user if you only want it in the current project.
Claude Code signs in through a loopback address on your own machine, so VISC's approval page says so explicitly. Approve it only if you started the connection yourself, from that machine.
VISC is a standard OAuth 2.1 authorization server. A client can connect if it supports:
Discovery starts where every MCP client starts: request https://visc.cat/mcp/me without a token and you get a 401 with WWW-Authenticate: Bearer resource_metadata="https://visc.cat/.well-known/oauth-protected-resource", scope="…". Follow it to the resource document, then to https://visc.cat/.well-known/oauth-authorization-server for the endpoints. The full flow, and the plain-HTTP alternative at https://visc.cat/api/v1/me/{tool}, are in tools.md.
Things worth asking for once the connection is live:
Two pages on VISC are yours to watch:
How approving works. VISC sends you no notification for a proposal: your assistant gives you a link, https://visc.cat/on/pendents?proposta=…, that opens your review page on that proposal (it asks you to sign in first if needed). You can also open it from your dashboard, «Propostes pendents». Untick what you don't want, edit, then press the button at the bottom of the card. Proposals you leave alone expire after 30 days, and nothing in them ever happened.
Each connection may read 500 times, write 50 times and file 5 support tickets per day. Beyond that it gets quota_exceeded until the next day. These are generous for real use and deliberately too small to scrape with. An act sent with submit:agenda also counts against your own daily limit for acts — the same one as when you use the form — and the answer tells the assistant how many you have left.
Content must be in Catalan, and every proposed topic entry must carry a source URL. Both are checked before a proposal is stored, so an assistant that ignores them gets an error rather than wasting your review time. The writing contract is authoring.md.
| What you see | What it means |
|---|---|
| The client asks for a client ID and secret | It found no way to register. Leave the fields empty and retry; if it still asks, report it — VISC supports both CIMD and dynamic registration, and never issues a secret |
| invalid_redirect_uri when registering | A redirect URI is not https (or http on loopback), or the URIs point at more than one host |
| invalid_request: redirect_uri … not registered | The redirect the client used is not in its own metadata document. Nothing you can fix in VISC — report it to the client |
| invalid_client: metadata document could not be fetched | The client's client_id URL is unreachable or is not JSON |
| The approval page says the request expired | Authorization requests live 10 minutes. Start the connection again |
| Tools appear but every call says unauthenticated | The connection was revoked, or you connected to https://visc.cat/mcp (anonymous) instead of https://visc.cat/mcp/me |
| quota_exceeded | The daily cap for that connection. It resets at midnight UTC |
Community agents. A community can seat an agent as a member of its own, with its own public handle and its own permissions inside that community — that is set up by a community administrator from the members page, and it is a different thing from connecting your personal assistant. See tools.md.
Everything the public pages render is also available as JSON, served from a CDN, free to read, no key, no account. This document is the contract; the machine-readable list of files is the manifest:
https://visc.cat/data/agents/index.json
Read the manifest first. Anything not in it does not exist — do not invent URLs.
GET https://visc.cat/data/agents/index.json
{
"version": 1,
"about": "…",
"docs": ["https://visc.cat/llms.txt", "https://visc.cat/agents/tools.md", "…"],
"params": { "localityCode": "Six-digit municipality code. List: /data/agents/localities.json …", "…": "…" },
"datasets": [
{
"id": "locality",
"title": "Locality profile",
"description": "Population, area, elevation, postal code, website, images, intro, culture, …",
"urlPattern": "/data/localities/{localityCode}.json",
"params": ["localityCode"],
"index": "/data/agents/localities.json",
"kind": "static",
"format": "json",
"cacheSeconds": 14400
}
]
}https://visc.cat/data/agents/localities.json — every municipality with code, name, slug, comarcaCode, comarca, vegueriaCode, provinceCode, lat, lng.
Families, so you know where to look — the manifest has the exact patterns:
If you intend to author content for a user to paste (see authoring.md), read first:
The same data, as tools. Both are unauthenticated and closed-world (they only ever read the files in the manifest and the public pages' own JSON) and nothing on them writes: the prepare_* tools below hand back a filled form link for a person to send. Both apply a soft limit of 120 requests per minute per client.
MCP — https://visc.cat/mcp, Streamable HTTP, stateless (no session id; POST JSON-RPC, JSON responses). Add it to any MCP client as a remote server with no auth. Tools, all annotated readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false:
| Tool | What it returns | ||
|---|---|---|---|
| list_datasets | the manifest | ||
| get_dataset | any manifest file by id + {params} | ||
| search_localities | place name → code, slug, comarca, coordinates (accent-insensitive) — start here | ||
| get_locality | profile + territory row + page path | ||
| get_comarca | comarca profile + its municipalities | ||
| get_upcoming_events | what is on: a town's, a comarca's or Catalonia's public agenda plus the communities' events — see What's on below | ||
| get_open_incidences | open civic incidences, optionally for one locality | ||
| get_locality_topics | a locality's topic pages (empty list when none) | ||
| get_topic | one topic: intro + entries with readable text (a diagram is «[Diagrama]» + hasDiagram, a table «[Taula: N files]» + hasTable — send the person to the page for those), source kind, links, score | ||
| get_local_news | headlines for a locality (all scopes) or a comarca | ||
| get_subject | one territorial subject (subjectID, e.g. natura, xifres) for Catalunya or narrowed with `scope: { kind: comarca\ | vegueria\ | province, code } (not for bolets / llengua): total, localityCount, sampled, byType, byComarca, generatedAt, itemsInFile and the public page path; items only with includeItems: true (default 20, max 200 via limit`) |
| search_places | places of a kind near a town or a point — see Places near somewhere below | ||
| get_locality_info | a municipality's information-page data by localityCode, every section or a sections subset (water, finances, services, pulse, feina, habitatge, subvencions, connectivity, energy, waste, concerns, elections, openness): per section { link, available, data } — available: false means no file for this town, not an error — plus the information page path. link is the section's anchor on that page | ||
| review_page_readability | audit one public VISC page as a crawler sees it (no JavaScript): missing/over-long title, no meta description, skipped heading levels, images without alt, empty links, dead internal links, thin server-rendered content. Pair it with report_feedback — a finding nobody hears about is not a finding |
Where to sleep, ski, eat, swim or go out near a town — from VISC's own lists, before the web. Input: kind, and localityCode or lat + lng; radiusKm (default 15, max 60), optional query (words in the name or detail), types (the subject's byType keys, e.g. camping) and limit (default 20, max 100).
Kinds: allotjament, estacions-esqui, refugis, hostaleria, lleure, equipaments, museus, cinemes, teatres, piscines, esports, platges, parcs, jocs-infantils, serveis-publics, salut, farmacies, seguretat, cures, escoles, entitats, productors, patrimoni, natura, cims.
Each place, nearest first: name, type, detail, localityName, distanceKm (approximate: true when measured to its town's centre), lat/lng and page, its visc.cat page. The rows come from the complete comarca lists of the subjects — static files, nothing else; source names them, and OpenStreetMap rows carry the ODbL credit. An empty list is VISC's answer: say so before you search the web, and label what you find there «de la web».
Every public agenda VISC gathers — the Agenda Cultural, festes locals, the ajuntament's own agenda, Diba libraries / museums / parks, fairs, cinema en català, theatre, approved «Publica el teu acte» acts — plus the communities' public events, soonest first.
Each event: title, day, endDay, time, endTime, kind (act one-off and timed · day all-day · scheduled exhibition, course, season), location, localityCode or communityID + eventID, source, url, ticketURL, isFree, priceText, summary, lat / lng and distanceKm for acts outside the town. An offer already running sorts as today, and acts come before seasons on the same day. total counts every match before limit; sources names the files read.
Communities are read from what their public pages already publish — nothing a visitor could not see.
| Tool | What it returns |
|---|---|
| search_communities | communities with a public page (associations, clubs, AFAs, colles, neighbours, businesses…) by localityCode, query (name / description), profile (afa, sports_club, colla, neighbours_association, cultural_association, cooperative, local_business…) or type: slug, name, type, profile (when filtered by it), localityCodes, page. Check here before preparing a new community |
| get_community | one community's public page by slug: profile, towns, description, public contacts (web, email, phone), membership tiers, upcoming events (ISO dates), public posts, the public board, how to join, page and agendaPage. A private community is its name and how to ask in — nothing more |
Resources: visc://docs/{overview|tools|authoring|examples} (these docs) and visc://data/manifest. Errors come back as tool results with isError: true and a JSON body { "error": "<code>", "message": "…" } where error is one of invalid_input, not_found, quota_exceeded, internal.
HTTP — GET https://visc.cat/api/v1/{tool}?param=value for every tool above, same parameters as query string, same JSON result. Lists and objects: sections=water,finances, scope=comarca:40, includeItems=true. GET https://visc.cat/api/v1 lists the operations with their JSON-schema parameters. Responses are CDN-cached (Cache-Control matches the freshest file the call read); errors are { "error": "<code>", "message": "…" } with a matching HTTP status.
VISC is meant to be added to, not only read. Every creatable thing with a public form has a prepare_{kind} tool generated from that form's own contract: you send what you know, VISC judges it exactly as the form will and answers a https://visc.cat/…?draft=… link. The person opens it, the form is filled, and they send it with their own account and their own daily limits. Nothing is written — not even a draft — until they do.
| Tool | The link opens | Fields |
|---|---|---|
| prepare_agenda_submission | /publica — «Publica el teu acte», an act for the town agenda (a moderator publishes it) | title, localityCode, dateStart, dateEnd, timeStart, location, description, link, ticketURL, isFree, priceText |
| prepare_incidence | /{town}/informacio with the incidence wizard open, the pin placed | localityCode, category, title, description, lat, lng, street, number, postcode, subdivisionCode, subdivisionName, objectID |
| prepare_event | /{community}/agenda with «Nou esdeveniment» open — only for a member who may create events | communitySlug, title, description, startsAt, endsAt (ISO 8601 with offset), type, location, tags, activityKinds |
| prepare_community | /crear, the community creation page — the person becomes its owner | name, slug, description, profile, type, subType, localityCodes, isPublic |
| prepare_recipe | /{town}/receptes with «Afegeix una recepta» open — published under the person's name | localityCode, title, kind, dishName, intro, ingredients[], steps[], servings, prepMinutes, cookMinutes, tags[] |
Every answer is { url, ready, errors, missing, personToFill, warnings, opens }. errors is field-keyed (title: too-long, dateStart: past, ticketURL: invalid) — a wrong value is dropped from the link, never a refused call. missing lists required fields you did not send; personToFill the ones only the person may type (an organiser's name, a contact, a photo — never carried in a URL). Hand over the url when ready is true, or fix and call again. Lists (ingredients, steps) are one item per line; over HTTP GET they may be one newline-separated value. A link is short by design: a very long recipe answers draft: too-long. Civic acts that carry a person's signature (an initiative, «jo també») have no tool — they are always the person's own tap.
A person can let your agent read their own VISC data: their communities, inscriptions, saved events and public profile. Standard OAuth 2.1 with PKCE (S256), public clients only. Your client_id is the https URL of your Client ID Metadata Document ({ "client_id", "client_name", "redirect_uris" }), or, if your client cannot host one, register at POST /oauth/register (RFC 7591) and use the client_id it returns. Localhost redirect URIs are accepted for desktop/CLI clients.
Scopes today: read:own, read:profile, read:community, propose:content, propose:profile, propose:events, propose:incidence, submit:agenda, watch, draft:governance, feedback. read:own unlocks: get_my_profile, get_my_communities, get_my_inscriptions, get_my_saved_events; read:profile and propose:profile are in The person's vincles and plan profile below, watch in Watches below. Every authenticated call is metered per grant per day by the person's plan — Veí (free): 500 calls, 50 writes, 2,000 database documents read; VISC+: 5,000 calls, 300 writes, 20,000 documents — whichever runs out first (quota_exceeded beyond; on Veí the message says what VISC+ would allow, never push it on the person) — and never CDN-cached. A personal read like get_my_vincles costs a handful of documents, so the document cap only bites a loop that re-reads the same data; read once per conversation and work from the answer. The person sees every grant, its scopes and today's reads on their account page and can revoke it at any time — revocation takes effect within a minute even while an access token is still valid.
With submit:agenda — its own line on the consent screen — submit_agenda_event sends an act to a town's agenda in the person's name, into the same moderation queue as their own «Publica el teu acte». The fields are those of prepare_agenda_submission plus organizerName (required) and organizerContact (private: only moderators see it), and an optional idempotencyKey (a retry with the same key returns the same submission; a different act under it is idempotency_conflict). The act:
Person grants only (a community seat proposes events for its own agenda instead). Annotated idempotentHint: false: without a key, a retry sends twice. When the person would rather check and send it themselves, use prepare_agenda_submission.
With propose:content / propose:incidence the agent can propose — never publish. A proposal lands on the person's review page; they toggle items, edit, publish through VISC's own forms, or reject with a reason you read back. Every published record is marked as agent-prepared.
| Tool | What it proposes |
|---|---|
| propose_topic | a whole new topic page from a dossier written per authoring.md — # Títol, intro, ## sections, one bullet per entry, one source URL per entry |
| propose_topic_entries | entries for an existing topic (localityCode, topicSlug, entries[] with markdown, sourceURL, sourceKind, optional replacesEntryID) — read get_topic first |
| propose_incidence | a civic incidence the person described to you (category, title, description, the point as lat + lng or point: { lat, lng }, street, number, objectID) — check get_open_incidences first |
| propose_community (propose:content, person only) | a new community the person creates with one tap from their review page (community: name, profile or type, localityCodes, description, slug, isPublic) — they become its owner, your agent never a member. The receipt also carries formLink, the same community as a filled /crear link. Check search_communities first |
| propose_event (propose:events, seat only) | one event for the community you are seated in (title, description, startsAt, endsAt, type, location, tags) |
| propose_thread (seat only) | one post for the community feed (title, markdown, threadKind) |
| propose_month_plan (propose:events, seat only) | a month's events[] + threads[] in one batch (month as YYYY-MM, summaryCA) — the admin toggles items and publishes the rest in one pass |
The last step of a barri campaign: a community (propose_community), evidence on the map (propose_incidence), a dossier (propose_topic), the initiative, then a watch on the answer (create_watch). The person publishes it with one tap; it is then open for adhesions.
Input: kind (petition to the ajuntament · municipal · ilp to the Parlament), title, summary, body in markdown, the instància's exposo and sollicito, localityCodes (main town first), optional barri by name, eligibility (anyone or geo_present) and an optional signatureGoal. All in Catalan. Ground it first (get_locality_info, get_open_incidences, get_locality_topics); the receipt's warnings name a similar initiative already collecting, often better joined than duplicated.
Signing — the person's own signature included — and presenting the instància at each seu electrònica stay the person's acts. No tool signs, counts or delivers.
VISC works around a person's vincles — the towns and barris they live, work, were born in, have family in, want to go to, or starred — and their plan profile («Afina el teu pla»: who comes along, free time, activities, travel, budget and goals, tastes). The agenda, alerts, search, the week plan and their personal trail all read them. Most people fill in little; their assistant can help, with their consent.
| Tool | What it does |
|---|---|
| get_my_vincles (read:profile) | their places and starred places — a summary by default, every row with detail: true; see Reading the vincles below |
| get_my_preferences (read:profile) | the plan profile: household (members with kind, birthYear, nickname), time.set and time.free (per day: morning · midday · afternoon · evening; null when set is false — they never said, which is not "always free"), activities[] (kind, stance: do · watch · learn · avoid), travel, habits, tastes, changedAt. exists: false = never set |
| get_my_next_steps (read:profile) | start here: gaps[] (what is missing, why it matters, the fix fields), steps[] (their personal trail), communities.mine (role and what it lets them do), communities.suggested (public communities in their towns matching what they do or want to learn), communities.missing (activities with no community in their home town — propose_community can start one), agentCan, never |
| propose_profile_update (propose:profile) | ONE proposal with any of: vincles[] (localityCode, relation, remove), household (replaces it), time (free, latestEnd; replaces it), activities[] (merged by kind + members unless replaceActivities), travel, habits, tastes |
| propose_person_vincle (propose:profile) | ask another VISC person for a vincle by their handle (username, as on /u/{username}), with how the person labels them (relation: friend · family · neighbour · colleague · acquaintance) and an optional Catalan message. Approving it sends the request; the other person accepts or not in VISC, and a refusal is never reported (pendingRequests in get_my_vincles just stops listing it after 30 days). Only handles the person gave you — VISC has no people search, by design |
By default a summary: home (the town they live in — live beats own_home, then work, roots, visits), summary (placeCount, byRelation, byKind, topPlaces strongest tie first, starredCount, starredByRelation), topStarredPlaces, collectedEscuts, people and relationsYouCanPropose.
people is their vincles with other people: count, people[] (the 20 most recent; all with detail: true) with username, displayName, relations (how the person labels them) and since, and pendingRequests (handles they asked who have not answered). That is all VISC ever tells an agent about someone else — never their places, plans, preferences or other vincles.
With detail: true, every row: places[] and starredPlaces[] (restaurants, venues, heritage, nature they starred or checked in at). A place has code, kind (municipality · districte · barri · espai_natural), name, localityCode and localityName (a barri's or districte's town), within (its districte or sector), page and relations; storedAs lists the codes when one barri was saved twice (from its districte page and its city's).
Names come from VISC's own indexes. unresolved: true with name: null means VISC has no name for that code: say so, never guess one.
Only what the person told you — never infer a home, a birth year or a child. here («Hi soc») is a geolocated check-in the person makes on their phone and cannot be proposed; live and born hold on one municipality, so proposing a new one moves it (the receipt's warnings say from where). Items already true are skipped with a warning; a proposal with nothing to change is invalid_input. Sections go through the same sanitizer the profile uses, so what the person approves is exactly what is saved. Never shared with communities; person grants only.
A watch follows what a town publishes: its ple topics (ple_topic, optionally one bucket such as habitatge), its open grant calls (subvencions) or its job postings (feina, optionally offer or public_call), filtered by words (any of them, matched at the start of a word, accents ignored). An alert zone (alert_zone) is a point and a radius (1–50 km) over fires, power cuts and Pla Alfa. The person's plan sets the room: Veí 1 watch + 1 zone, VISC+ 20 + 10.
| Tool | What it does |
|---|---|
| list_watch_hits (watch) | every watch with what it matches today, newest first (hits[]: title, subtitle, at, url, isNew), newCount since the person last looked, inPlan: false for a slot paused after VISC+ lapsed. Alert zones are listed, not evaluated (live feeds: send the person to /avisos). onlyNew: true for what is new only. Read-only — the person's «nou» marks stay theirs |
| create_watch (watch) | a proposal for one watch (kind, localityCode, keywords, bucket, postingKind) or zone (point or a town's centre, radiusKm, minSeverity, alertKinds), with an optional label and push (town kinds; the 08:00 run pushes what is new). Refused with quota_exceeded when the plan is full — the message says what to do; the receipt's room says how full it is |
Nothing changes until the person acts, and VISC does not notify them — you do. Every propose_* receipt carries:
On the card they see each item (a vincle as «Hi visc: Vacarisses», with the town it moves from; a profile section in words, before and after; a topic entry as editable text…), untick what they do not want, edit the text, and press «Publica N de M» — «Aplica» for profile changes, vincle requests and watches — or «Rebutja» with a reason. Approval runs through the same paths as their own taps (the vincle panel, /on/perfil, the forms), so their other devices and every page see the change. They can also reach the page from their dashboard, «Propostes pendents». Tell them what you proposed and why, give them the link, then read the decision back with get_proposal — a rejection's rejectReason and decisionNote say what to change.
| Tool | What it does |
|---|---|
| list_my_proposals, get_proposal, withdraw_proposal | the lifecycle: pending → approved / partially_approved / rejected / withdrawn / expired; rejected ones carry rejectReason (ungrounded, wrong_language, duplicate, off_topic, too_long, other) and a decisionNote — change what you propose next |
| report_feedback, request_support (scope feedback) | file a ticket for the VISC team — a tool misbehaved, a source 404s, you need a dataset or a tool. Five per day; identical reports collapse |
Rules the server enforces before storing anything: Catalan text (not_catalan), one source URL per topic entry (missing_source), an existing published topic for entries (not_found), at most 60 items / 256 KB per proposal, and an idempotencyKey you choose — retrying with the same key returns the same proposal, reusing a key with a different payload is idempotency_conflict. Proposals expire after 30 days. Over HTTP these are POST https://visc.cat/api/v1/me/{tool} with a JSON body.
A community can seat your agent as a member of its own: its own public handle (agent-{community}, a handle no person can claim), its own permissions inside that community, and no way to sign in. An admin creates it from the community's members page and hands you a refresh token — there is no browser redirect, because a community's runtime is usually a cron. Use it exactly like a person grant's refresh token (grant_type=refresh_token at /oauth/token), and call the same /mcp/me and /api/v1/me/{tool} endpoints.
A seat passes two gates on every call: the scopes the community granted the agent, and the seat's own community permissions. A seat without events.create gets forbidden on propose_event, exactly as a member without it cannot create an event by hand — and no permission a community admin adds to the seat can take it outside what an agent seat may ever do.
| Tool | What it does |
|---|---|
| get_community_bundle (read:community) | one private snapshot of the community: config and enabled features, published events ±12 months, published threads of the last 90 days, poll aggregates (tallies only once a poll closed), counts, and the locality's public dataset paths. Never a member roster, never a uid or an email. Baked nightly — read generatedAt; there is deliberately no change feed |
| draft_poll, draft_proposal (draft:governance) | create the record UNPUBLISHED, with its own model's draft status. Invisible to voters until an admin opens it from the community's own page |
| list_my_drafts, update_draft, delete_draft | your own undecided drafts. A draft that vanishes from the list was published or discarded by an admin — a published record is no longer yours to change |
A person grant with read:community can also call get_community_bundle, naming a community by id or slug; it honours the person's own membership, so an agent never sees more of a community than the person who delegated it.
Proposals from a seat are community content: they land on the community's review page, every active member can see what the agent is preparing, and whoever holds the kind's create permission decides. Published records carry "Agent de la comunitat" rather than "preparat amb un agent".
Initiatives have no prepare_ link tool yet (propose_civic_initiative drafts one for a signed-in person) — and signing one never will be a tool: it is the person's own act. Proposing tips and map markers, native drafts of forms and courses (an agent seat deliberately cannot create either by hand, so it cannot draft one), baskets and inscriptions (propose:commerce), MCP Apps review panels and the Tasks extension are next, on the same OAuth flow and MCP server. Money never passes through an agent, and nothing public is ever published without a human: an agent cannot move money, join or leave, change permissions, message people, delete anyone else's content, or send anything. No tool exists for those, and no scope can express them.
How to write one markdown string that a VISC user pastes into a creation form to get a rich, fully-populated page. Today this works for locality topics (citizen dossier pages); future importers (agenda programs, directories, FAQs) will reuse the same contract.
The loop: you compose ONE markdown string following this contract → the user opens the creation form (for topics: their locality page → Comença un tema) → pastes it into the Descripció field → reviews the detected sections and items in a preview panel → submits. Parsing is deterministic — the same string always produces the same page, no AI on the platform side — so the quality of the result is entirely in the string you write.
| You write | It becomes |
|---|---|
| # Títol del tema (first line) | the page title (max 80 chars) and its URL slug |
| prose before the first ## | the page description (max 4,000 chars; overflow is cut at a paragraph break with a visible warning) |
| ## Secció | a section — its title opens every derived entry as a bold lead line |
| - element at column 0 (also * / 1. ) | one entry (card) per bullet, when the section has 2 or more |
| indented lines under a bullet | stay inside that entry (wrapped text, nested lists) |
| a section with prose and fewer than 2 bullets | one single entry with the whole section body |
| a short paragraph (≤200 chars) right after a ## | a lead-in, merged into the section's first entry |
| longer prose between bullets | its own entry |
Standard markdown works inside one entry: [text](https://…) links and bare URLs (each URL on its own line also gets a link preview card — one fetch per URL, so use real, reachable links), YouTube URLs become a playable embed,  images (https only — a paste cannot upload files), GFM tables, > quotes, ``` `mermaid `` diagrams, bold, italics, strikethrough, code . 900 818 482 dials on tap and address` opens the mail client — neither href may contain spaces.
Entries render as cards in a masonry grid; each card's width is derived from its heft. Use it deliberately:
A good-looking page mixes them: a few Large anchor entries (the key report, a table, a photo), Medium analysis entries, Small link/fact entries.
| Limit | Value |
|---|---|
| whole paste | 40,000 chars |
| title | 80 chars |
| description | 4,000 chars |
| one entry | 4,000 chars (auto-split past it, with a warning) |
| entries worth creating | ~10–40 (the page shows 60 max) |
| detection floor | at least 1 section AND 3 entries, or no import is offered |
# Abocador de Coll Cardús i les olors
El CTR tracta residus de tota la comarca i les queixes per pudor
s'acumulen des de 2019. Aquesta pàgina aplega documents oficials,
premsa i aportacions veïnals per seguir el cas.
## Documents oficials
- **Resolució de l'ARC (2023)** — obre expedient de control d'olors.
https://arc.gencat.cat/exemple-resolucio
- **Informe municipal d'olors** amb els mesuraments de 2022 i 2023.
- Taula de llindars aprovats (la taula fa l'entrada d'amplada completa):
| Paràmetre | Llindar |
| --- | --- |
| Unitats d'olor | 5 ouE/m³ |
## Cronologia
Els fets principals, dels més antics als més recents.
- **2019** — primeres queixes veïnals registrades a l'Ajuntament.
- **2021** — moció aprovada al ple per exigir mesures correctores.
- **2023** — l'ARC obre expedient i imposa mesures.
## Premsa
- Reportatge comarcal sobre l'onada de queixes.
https://exemple-mitja.cat/reportatge
- https://www.youtube.com/watch?v=exempleFive concrete ways an agent works with VISC today. The contract behind example 1 is in authoring.md — read it first.
A user asks their assistant: "Prepara un tema sobre la festa major per al poble de Taradell."
The agent's loop:
# Festa Major de Taradell 2026
Tot el programa de la festa major en una sola pàgina: actes,
horaris i enllaços oficials, per votar i comentar els actes.
## Divendres 14 d'agost
- **19.00 — Pregó d'inici** a la plaça de les Eres, a càrrec
de la colla gegantera.
- **22.30 — Concert jove** al parc de Can Costa.
https://exemple-ajuntament.cat/programa
## Dissabte 15 d'agost
- **11.00 — Cercavila de gegants** pel centre del poble.
- **18.00 — Ballada de sardanes** amb la cobla local.
- **23.00 — Ball de nit** al pavelló.
## Enllaços oficials
- Programa complet en PDF a la web municipal.
https://exemple-ajuntament.cat/festa-major
- https://www.youtube.com/watch?v=exemple-aftermovieWhat made this work: real URLs, Catalan, one provenance, self-contained entries (each act repeats enough context to stand alone once votes re-order them).
A user asks: "Què passa aquest cap de setmana a Ripoll?" — no VISC account needed. The public, server-rendered pages an agent can read:
For structured answers, use the tools instead of scraping the page: search_localities → get_upcoming_events, get_open_incidences, get_locality_topics (and get_locality_info for the town's open data — water supplier, budget, jobs, housing — or get_subject to compare it with its comarca or Catalunya) on the MCP server (https://visc.cat/mcp) or as GET https://visc.cat/api/v1/{tool}; the raw files are in the manifest at https://visc.cat/data/agents/index.json (tools.md). What an anonymous agent cannot do: read community-internal content (member events, payments, threads) or write anything — to add content it prepares a link (example 4), and with a person's consent it acts for them (example 5).
Users who want their own assistant to prepare VISC content can hand it this prompt:
Read https://visc.cat/agents/authoring.md and follow its contract
exactly. Then write, in Catalan, a complete topic paste about
[TOPIC] for the municipality of [TOWN]. Ground every fact in
real, reachable URLs (official sources and local press only) and
aim for 3-5 sections with 10-25 self-contained entries, mixing
entry sizes as the contract describes. Return only the markdown
string, ready to paste.Replace [TOPIC] and [TOWN], review what comes back — especially that every URL is real — and paste it into the topic form.
A user asks: "L'Ateneu de Vacarisses fa un concert de tardor dissabte 7 de novembre a les 19 h a la plaça Major. Penja-ho a l'agenda."
Had the date been in the past, errors would say dateStart: past and the agent would ask again — a wrong value is never a failed call. The same pattern prepares an incidence (prepare_incidence, with the point and the street), a community's event (prepare_event, with the communitySlug from search_communities), a new community (prepare_community) or a town recipe (prepare_recipe).
Connected at https://visc.cat/mcp/me with submit:agenda, the agent sends the same act itself: submit_agenda_event with the fields above plus "organizerName": "Ateneu de Vacarisses" and an "idempotencyKey" of its own. The answer is { "status": "pending", "remaining": 4, "resetAt": "…", "public": false }: the act waits for a moderator, and the person has four acts left today — an assistant saves typing, it never multiplies a voice.
For a new entity — "Volem crear la colla gegantera del poble a VISC" — the agent checks search_communities (profile: "colla", localityCode), then calls propose_community with profile: "colla", the town and a Catalan description. The person creates it with one tap from /on/pendents and becomes its owner; the assistant never joins it. Signing an initiative, paying or joining a community stay the person's own tap.
Les dades públiques ja es poden llegir en JSON des de la CDN. Un servidor MCP i l'accés delegat des d'un compte d'usuari són al full de ruta. Si construeixes agents i vols que VISC hi jugui bé, explica'ns-ho amb el botó Envia feedback del peu de pàgina.