MCP og forbundne værktøjer
Forbind Nessie til MCP-servere, og par en ekstern agent, så den kan arbejde i Nessie som dig.
Hvad MCP er
Model Context Protocol er en lille, åben konvention til at beskrive værktøjer for en sprogmodel og kalde dem. En server erklærer, hvad den kan — en liste over navngivne værktøjer, hvert med et JSON-skema for sine argumenter — og en klient finder listen og kalder værktøjerne på modellens vegne. Den er bevidst kedelig: værdien er, at én integration, skrevet én gang, virker med alle modeller og alle produkter, der taler den.
Nessie står på begge sider af den
Det er værd at være præcis om, for de to halvdele er nemme at forveksle, og de ligger på bevidst forskellige stier.
- Udgående. Nessie er en MCP-klient. Du forbinder servere, som andre driver, og de værktøjer, de udstiller, bliver værktøjer, dine agenter kan bruge. Administrationsfladen er
/api/mcp/*. - Indgående. Nessie er også en MCP-server. En agent, der kører et andet sted — Claude Code eller Codex på en udvikleres maskine — kan kalde ind i dine tavler og dokumenter. Det endpoint er
POST /mcp, placeret uden for/apimed vilje, så de to modsatrettede betydninger ikke står ét stisegment fra hinanden.
Forbind en MCP-server til Nessie
Katalogposter og instanser
Der er to objekter, og forskellen betyder noget:
- En katalogpost er definitionen af en server — dens navn, transport og hvordan den autentificerer. Den skrives én gang og kan deles.
- En instans er den post, installeret på ét niveau, med de legitimationsoplysninger, der når frem til den. Installeres den samme post for to forskellige teams, får du to instanser.
De fleste rører aldrig nogen af dem direkte. Indgangen i admin er app-butikken på /admin/apps: den gennemser det samme katalog med forbindelsesdetaljerne skjult, og Connect på en liste opretter en instans. Operatører, der vil have de rå objekter, bruger /api/mcp/catalog og /api/mcp/instances.
Hvis en server ikke står i kataloget endnu, tager POST /api/mcp/discover en URL og returnerer, hvad serveren selv siger om sig selv, og POST /api/mcp/library/import henter en post fra det offentlige serverbibliotek. En første forbindelse kan også oprettes direkte fra en URL med POST /api/apps/custom.
Transporter
Nessie forbinder til eksterne servere over HTTP. To transporter virker: streamable HTTP (den nuværende MCP-transport) og den ældre HTTP+SSE-transport. Vælg http, medmindre serveren kun tilbyder sse.
Transporten stdio afvises for connectors, du selv skriver. stdio betyder, at MCP-serveren er en lokal proces, som værten starter, og at køre vilkårlige programmer inde i Nessie-serveren er ikke noget, en operatør meningsfuldt kan gennemgå. Servere, der kun udgives som en pakke til lokal kørsel, fjernes fra bibliotekimporter af samme grund. En ws-værdi findes i protokolfeltet og er ikke implementeret — en forbindelse, der bruger den, fejler, når Nessie forsøger at åbne den.
Hvordan Nessie autentificerer til serveren
En katalogpost angiver en af fem metoder: none, api_key, bearer, basic eller oauth2.
api_key er header-injektion, og posten angiver, hvilken header og hvilket præfiks der bruges — så Authorization: Bearer …, X-API-Key: … og X-Auth-Token: Token … er alle den samme metode, bare konfigureret forskelligt. Selve nøglen indsættes én gang med POST /api/mcp/instances/:instanceId/secret og kan aldrig læses igen; intet svar fra instansruterne bærer en legitimationsreference.
oauth2 kommer i to former. En server med faste endpoints har dem i sin katalogpost. En server, der udgiver standardmetadata, kræver slet ingen opsætning: Nessie læser dokumenterne for beskyttet ressource og autorisationsserver og opretter selv en klient via dynamisk klientregistrering eller via det klient-ID-metadatadokument, den udgiver på sin egen well-known-sti. Uanset hvad er håndtrykket POST /api/mcp/instances/:instanceId/oauth/start, efterfulgt af udbyderens redirect tilbage til GET /api/mcp/oauth/callback. State-tokenet er engangsbrug, ligger i databasen og er gyldigt i ti minutter, og PKCE bruges altid.
Én regel overrasker folk: selv en organisationsejer kan ikke knytte et personligt eller OAuth-token til en anden person. En delt legitimation er kun mulig for en API-nøgle-post, der er valideret som netop det; alt andet afvises. En legitimation, der tilhører en person, forbliver en legitimation, der tilhører den person.
Hvor legitimationsoplysningerne ligger
Connector-hemmeligheder og OAuth-tokenpakker gemmes i din egen Postgres-database, i formålsbundne AES-256-GCM-kuverter under deploymentets uafhængigt versionerede krypteringsnøglering, og adresseres kun via uigennemsigtige secret_*-referencer. De ligger bevidst ikke i den eksterne hemmelighedsvault, der rummer de andre Nessie-hemmeligheder. En produktionsdeployment, der ikke har konfigureret den krypterede butik, nægter at starte i stedet for at fuldføre et OAuth-håndtryk, som den ellers ville smide væk.
Hvor en forbindelse når til
En instans er installeret på et af seks niveauer: system, organization, project, team, channel eller user. Niveauet er et hårdt loft over, hvilke kørsler der kan bruge den, og tilladelser kan kun indsnævre det yderligere, aldrig udvide det — så en connector, du installerede med din egen konto, ikke stille og roligt kan blive organisationsdækkende.
Hvem der må installere hvor, følger samme form: organisationens ejere og administratorer styrer installationer på alle niveauer; alle andre installerer connectors på deres eget user-niveau og kan se delte installationer, de har adgang til.
At give en agent et værktøj
At forbinde en server giver ikke dens værktøjer til nogen. Når en instans installeres, prober Nessie den og projicerer hvert værktøj, den annoncerer, ind i værktøjsregistret — det er det, admin viser på /admin/advanced/tools: indbyggede værktøjer, MCP-værktøjer, bundle-værktøjer og executor-værktøjer på én liste, hver med kilde og status.
Et projiceret værktøj har en af tre statusser: active, pending_review eller disabled. Værktøjer fra en installation på delt niveau kommer som pending_review og skal godkendes på den side, før en agent ser dem; værktøjer fra din egen user-niveau-installation er aktive med det samme, fordi den eneste person, der er eksponeret, er dig. Gennemgang er tilbagevendende, ikke en engangsceremoni: finder en senere probe, at et værktøjs beskrivelse eller skema er drevet, går det tilbage til pending_review og tilbydes ikke, før nogen kigger på ændringen.
Hvilke agenter der så må kalde et aktivt værktøj, afgøres på to måder:
- En forbindelse oprettet via app-butikken kræver en eksplicit tilladelse. En agent får kun værktøjet, når en tilladelse nævner det, og tilladelsen tjekkes mod værktøjets aktuelle fingeraftryk, så et ændret værktøj kræver en ny beslutning.
- Ellers er værktøjet slået til som standard for agenterne inden for rækkevidde af dets niveau, og enkelte agenter slås fra på værktøjets detaljepanel.
En tilladelse nævner præcis én aktør — en rolle eller en agent, aldrig begge — og et afslag slår en tilladelse. For en forbindelse på user-niveau opstår spørgsmålet ikke: enhver agent, den person taler med, kan bruge den, og en udtrykkelig fra-kobling er det eneste, der holder den tilbage.
Et sted, hvor man let kigger forkert: /settings/accounts i admin er tilsluttede konti — Slack, postkasser, modelabonnementer og OAuth-forbindelserne til Linear, Jira, GitHub og Trello, der understøtter eksterne tavler. MCP-connectors findes på /admin/apps, og de værktøjer, de producerer, findes på /admin/advanced/tools.
Godkendelsesgates på værktøjskald
Nogle værktøjskald stopper og venter på en person. Når et gør det, fejler kørslen ikke: kaldet fryses — værktøjsnavnet, en hash af dets argumenter og nok tilstand til at genoptage — og en godkendelsesanmodning dukker op på /api/approvals, hvor nogen skal svare. Genoptagelse er idempotent, så en dobbelt godkendelse ikke kan køre kaldet to gange. Personen, der beslutter, ser et begrænset resumé af, hvad der spørges om; de præcise argumenter og den oprindelige kørsel forbliver på serveren.
Der er to forskellige gates, og de konfigureres forskelligt.
- Strukturelle gates er en egenskab ved visse indbyggede værktøjer og kan ikke konfigureres. Afsendelse af post fra en agents egen postkasse eller fra en tilsluttet, afsendelse af et Gmail-udkast, afbrydelse af en postkonto, oprettelse, ændring eller annullering af en kalenderbegivenhed, og en browserhandling, der ville skrive til et sted, browseren ikke er logget ind på, er alle gated på denne måde. De får et 24-timers vindue til at blive besvaret i stedet for de sædvanlige 30 minutter.
- Politikgates kommer fra politikregler på parret
tool/invoke. En regel, der tillader et kald, kan haverequiresApproval, og uden en verificeret godkendelse returnerer evalueringenAPPROVAL_REQUIREDi stedet for at køre. Regler evalueres deny-first og ordnes efter niveau.
Hvilken admin-skærm der opretter en requiresApproval-politikregel for et værktøj — datamodellen og håndhævelsen er begge på plads, men vi har ikke kunnet bekræfte den skærm, der skriver en sådan regel.
Forbind en ekstern agent til Nessie
Den anden retning. Nessie kører sin egen MCP-server på POST /mcp, over streamable HTTP, og den er stateless: hvert kald bærer sin egen legitimation og finder selv sin aktør, så der er ingen session at fastgøre en klient til én replika. ChatGPT, Claude, Claude Code, Codex eller en agent på nogens bærbare kan arbejde med dine tavler, dokumenter og kunder inde fra det værktøj, personen allerede bruger. Trin-for-trin-guiden til hver app er Forbind ChatGPT, Claude og andre AI-apps.
Hvad en parret legitimation faktisk er
Det er den del, du skal have rigtigt, for den oplagte mentale model — en API-nøgle med tilladelser påhæftet — er den forkerte.
En parret legitimation er aldrig en identitet. Den navngiver et menneske, og hvert værktøjskald kører som det menneske, mod de samme servicefunktioner, som HTTP-ruterne kalder. En agent kan derfor ikke nå noget, personen, der lånte den, ikke kunne nå ved at klikke. Tilladelser indsnævrer kun den rækkevidde; der findes ingen tilladelse, der udvider den.
Liveness læses igen ved hvert eneste kald, aldrig antaget fra tokenet: tilbagekaldelse, udløb, brugerens tokenversion, deres organisationsmedlemskab og deres aktuelle rolle. En nedgradering, en deaktivering eller et »log mig ud overalt« rammer agentens næste kald i stedet for først ved legitimationens udløb.
Tokenet er uigennemsigtigt, præfikset nag1_, gemmes kun som SHA-256-hash og lever i 90 dage. Det afvises med en specifik 403 på enhver rute undtagen MCP-endpointet — at præsentere det andetsteds er ikke et delvist resultat, man skal prøve igen, og det er det, der forhindrer, at »jeg lånte en agent mine tavler« betyder »jeg lånte den min konto«.
To måder at forbinde på
En app, der kan åbne en browser — ChatGPT, Claude, Claude Code, Codex — bruger MCP-autorisationsprofilen: OAuth 2.1 med PKCE (S256), dynamisk klientregistrering på POST /mcp/oauth/register, refresh-tokens og resource indicators. Appen sender personen til /settings/security, hvor de vælger, hvad den må, og hvilke af deres teams den når, og browseren vender tilbage til appen med en kode. Dens adgangstoken varer en time og fornyes; forbindelsen lever i 90 dage.
En kommandolinjeagent styrer ingen browser og kan ikke være vært for en callback-URL, så den parrer i stedet med device authorization grant (RFC 8628).
- Agenten kalder
POST /mcp/auth/devicemed enclientNameog descopes, den vil have. Den får tilbage endevice_code, en kortuser_code, enverification_uriog enverification_uri_completemed koden allerede i forespørgslen, plus poll-intervalog enexpires_in. Den udskriver URI'en. - En person åbner den URI, mens de er logget ind, på
/settings/security. De ser, hvilken agent der spørger, hvis konto den ville arbejde som, til hvornår, og præcis hvad den ville kunne gøre — og vælger Tillad eller Tillad ikke. - Agenten poller
POST /mcp/auth/tokenmeddeviceCodeog respektererauthorization_pending,slow_down,expired_tokenogaccess_denied. Ved succes modtager den{ access_token, token_type, scope, expires_at }.
Under alle omstændigheder er der et menneskeligt trin, fordi legitimationen arver en persons rettigheder, så en person skal vælge at låne dem. Intet her udsteder adgang fra ingenting. Forbindelse kan også slås fra for en hel organisation på /admin/security?tab=programs, og det svar tjekkes, når nogen tillader en forbindelse, ikke når en agent starter en.
Opdagelse
En uautentificeret POST /mcp svarer 401 med en WWW-Authenticate-header, der peger på /.well-known/oauth-protected-resource (RFC 9728), som nævner denne origin som autorisationsserver; dens metadata på /.well-known/oauth-authorization-server (RFC 8414) nævner registrerings-, autorisations-, token- og tilbagekaldelsesendpoints. Den kæde er alt, en klient har brug for, når den har adressen. For at finde adressen ud fra et domæne læser en agent /.well-known/ai-catalog.json, som peger på Server Card på /mcp/server-card (MCP Server Cards, SEP-2127). Device-grantens endpoints står i dokumentet for beskyttet ressource under x-nessie-device-authorization.
En deployment kan også svare på en anden, kortere adresse: Nessie Clouds https://nessie.works/mcp proxyes til API'et, og en klient, der kom ind på den måde, får den adresse tilbage som ressource, mens login forbliver på API'et. En redirect ville ikke hjælpe, for en klient afviser metadata, der nævner en anden adresse end den, den fik. Operatøren lister disse origins i NESSIE_MCP_ALIAS_ORIGINS.
Tilladelser og værktøjer
Tilladelser er bevidst grove — en tilladelse ingen kan forklare, er en tilladelse ingen sætter korrekt. En forbindelse, der når mere end ét team, lister dem med nessie_team_list, og hvert andet værktøj nævner så sit teamId.
| Tilladelse | Når |
|---|---|
boards_read | Projekter, tavler og opgaver, med deres kommentarer, filer, labels, typer og tjeklister |
boards_write | Oprettelse, redigering og flytning af opgaver, og alt på dem |
documents_read | Vidensområder, dokumenter og regneark |
documents_write | Udarbejdelse og redigering af dem, og anmodning om at udgive et |
clients_read | Kundeindbakken, kontakter, kontaktlister, nyhedsbreve og kontaktformularer |
clients_write | Noter, overtagelse, tildeling og lukning af samtaler, kontaktlister og forberedelse af nyhedsbreve |
clients_send | Alt, en kunde modtager: et svar, en første e-mail eller en sms. Aldrig afkrydset, medmindre personen selv afkrydser det |
website_tools | Sideværktøjerne på dit teams registrerede websted, betjent i en hostet browser, du kan styre. Aldrig afkrydset, medmindre personen selv afkrydser det |
Et kald uden den tilladelse, det har brug for, kommer tilbage som et værktøjsresultat, der navngiver den tilladelse, der skal bedes om, ikke som en transportfejl, så modellen kan rapportere noget nyttigt i stedet for at prøve igen mod en mur.
Der er ingen separat familie af værktøjer til eksterne trackere. En tavle er en tavle, uanset om dets opgaver stammer fra Nessie eller spejles fra Linear, Jira, GitHub eller Trello, så ét værktøjssæt dækker begge, og hver opgave siger, hvilken den er. Det, der adskiller sig, er skrivning: en tavle, der spejles fra en skrivebeskyttet kilde, afviser en skrivning med ord og fortæller agenten, at det andet system ejer opgaven, og at et nyt forsøg ikke hjælper.
At udgive et dokument er en godkendelse, aldrig en tilladelse
Agenter udarbejder; en person udgiver. Den regel håndhæves for Nessies egne agenter ved at afvise en agentaktør helt — men en parret legitimation løses som en person, så den afvisning kan ikke fange den. Gaten skal ligge et andet sted.
Så nessie_doc_publish udgiver ikke. Den åbner en knowledge.page.publish-godkendelse — den samme, en Nessie-agent åbner — og returnerer { status: "awaiting_approval", approvalId }. Polling returnerer den samme anmodning i stedet for at åbne en anden. Beslutningen træffes, som alle andre udgivelsesbeslutninger i Nessie træffes: af en person, om det dokument, i det øjeblik det findes.
Der er bevidst ingen udgivelsestilladelse. Der var én — et flueben ved parring, der sagde, at denne agent må udgive — og den blev udfaset. Den afgjorde én gang for alle, og i halvfems dage, et spørgsmål, produktet stiller pr. dokument alle andre steder, og den afgjorde det, før dokumentet fandtes, så personen, der satte fluebenet, ikke kunne vide, hvad de gik med til at udgive. nessie_doc_publish kræver documents_write, fordi det at spørge ikke er gratis — det læser siden og stiller en beslutning foran nogen — men den tilladelse giver ingen rettighed til udgivelse.
To identiteter registreres på anmodningen, og skelnen er bærende. Anmoderen er legitimationen, aldrig den person, den handler som. Den påkrævede godkender er den person, og kun de må svare. Havde anmodningen navngivet personen som anmoder, ville reglen, der forhindrer nogen i at godkende deres egen anmodning, diskvalificere den ene person, der er berettiget til at beslutte.
Se og tilbagekald, hvad der er parret
En persons egne parrede agenter står på /settings/security, med en etiket og en tilbagekaldelseskontrol for hver. En ejer eller organisationsadministrator ser hver legitimation i organisationen på /admin/security?tab=programs — hvad hver hedder, hvad den må, om den er aktiv, og hvis konto den låner — og kan tilbagekalde enhver af dem. Den personlige liste forbliver kun for en selv: en liste over aktive legitimationer er en liste over fodfæste, ikke almindelig læsning.
Skrivninger foretaget gennem en legitimation tilskrives det lånende menneske og bærer legitimationens id i audit-metadata, så loggen kan skelne en persons egen redigering fra en, deres agent foretog for dem.
Hvad der ikke er tilgængeligt endnu
Eksplicit, fordi kløften mellem en protokols evner og en given servers evner er der, dokumentation normalt slår fejl:
- Chat, kanaler, kørsler og agenthåndtering eksponeres ikke over MCP.
- Et program forbereder et nyhedsbrev, og en person sender det: intet sender, planlægger eller sletter en kampagne, og selve e-mailen skrives i designeren.
- Sammenkædning og sammenlægning af kontakter, ændringer af CRM-skemaet, importer og kanalopsætning forbliver hos en person i browseren.
- Tilslutningsafbryderen er en indstilling på organisationsniveau. Overstyringer på team- og personniveau er ikke noget, et team eller en person kan sætte i dag.