Add an MCP server for askgod at <askgod_server_address>/mcp.#9
Add an MCP server for askgod at <askgod_server_address>/mcp.#9
<askgod_server_address>/mcp.#9Conversation
2b3a570 to
fe84c16
Compare
|
@stgraber Le lint semble chialer sur des fichiers que j'ai pas touchés, sais-tu pourquoi? |
|
@Res260 try rebasing now. I've just pushed a whole bunch of fixes to modernize things and sort out all the newer lint. |
2b402c2 to
43f79a0
Compare
|
@stgraber everything should be good now |
|
Other than the API change mentioned above, this is going to need quite a few updates:
On the styling front, our normal pattern for commands is to have them start with a capital letter and end with a period. It looks like all the newly introduced comments fail to follow the existing pattern. We've also recently been putting I also am quite concerned about having validation logic duplicated in both the REST and MCP endpoints, especially things like scoreboard filtering or the validity of a team who's attempting to submit a flag. As someone with zero interest in the MCP stuff, I'm not likely to remember to update that code so we may well end up with submissions allowed under MCP which aren't on REST, that would be bad. My preference would be for the MCP stuff to put together a regular http.Request and call the REST endpoint internally so it would be guaranteed to go through the exact same logic as a normal REST query. If that's impractical, then the logic should be extracted from the REST endpoint and be put somewhere that can be called from both REST and MCP with neither of the handlers performing any additional validation on the submitted data. I also think that the trolling/nagging logic probably ought to be configurable. Oh and speaking of configuration, the entire MCP stuff should be an optional feature that needs to be enabled in the server configuration. |
53a5e31 to
5ae26c3
Compare
|
Update: J'ai refactor le tout. Le au lieu de
Still todo, je ferai à la fin quand le review sera fini, idem pour les signoff
De quelle commande on parle? Je sais pas si c'est encore pertinent suite au refactor.
Fixed
Done, c'est en effet plus clean
Retiré altogether
Done Donc j'attend le review final et je retravaille les commits |
|
Ça me prend le re-shuffle des commits pour pouvoir faire le review. Je review toujours commit par commit dans l'ordre et m'attend généralement à ce que le codebase soit compilable à chacun de ces points pour pouvoir être capable de bisect dans le future sans avoir une batch de commits brisés qui font skipper le bisect. |
…e `COPY` step. docker-compose: restart askgod-server on failure seed-data: fix seeded IPs so they work with Docker Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
…rver Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
…od history` Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
… to `askgod submit` (based on various AI Agent’s environment variables, this can be disabled using `--no-ai-autodetect` or using the `ASKGOD_DISABLE_AGENT_AUTODETECT` environment variable). Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
It has only one tool: Submit a flag. The MCP server is disabled by default and can be enabled with `mcp: true` in the askgod config. Internally, it uses the REST method calls to limit code duplication to a minimum. Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
|
@stgraber C’est fait! J’ai également retiré le refactor de la méthode qui retournait le Team selon le IP, les diffs sont pas mal plus clean sans ce refactor. |
Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
Signed-off-by: Émilio Gonzalez <little.moon6016@fastmail.com>
| value INTEGER NOT NULL DEFAULT 0, | ||
| submit_time TIMESTAMP WITH TIME ZONE, | ||
| notes VARCHAR, | ||
| ai_agent BOOLEAN NOT NULL DEFAULT FALSE, |
There was a problem hiding this comment.
I think a source field as a string would be more flexible in case we ever want to differentiate other flag submission sources.
| Description string `json:"description" yaml:"description"` | ||
| ReturnString string `json:"return_string" yaml:"return_string"` | ||
| Value int64 `json:"value" yaml:"value"` | ||
| AIAgent bool `json:"ai_agent" yaml:"ai_agent"` |
There was a problem hiding this comment.
I'd make that to be Source here too as a string.
| AdminScorePost `yaml:",inline"` | ||
|
|
||
| ID int64 `json:"id" yaml:"id"` | ||
| AIAgent bool `json:"ai_agent" yaml:"ai_agent"` |
There was a problem hiding this comment.
Should be Source on this one too
|
|
||
| Flag string `json:"flag" yaml:"flag"` | ||
| Flag string `json:"flag" yaml:"flag"` | ||
| AIAgent bool `json:"ai_agent" yaml:"ai_agent"` |
There was a problem hiding this comment.
Can you make this Source as well but we'll want to limit the number of valid values to:
- "" => compatibility mechanism, we'll translate it to "unknown" internally
- "cli" => human submission through CLI
- "cli+agent" => agent submission through CLI
- "mcp" => submitted through the MCP server
- "web" => human submission through website
- "web+agent" => agent submission through website
That should cover all the cases we care about while giving us some flexibility in the future.
| metricSubmitTeam.WithLabelValues(strconv.FormatInt(team.ID, 10), "invalid").Inc() | ||
| _ = r.eventSend("flags", api.EventFlag{Team: *team, Input: flag.Flag, Type: "invalid"}) | ||
| logger.Info("Invalid flag submitted", log15.Ctx{"teamid": team.ID, "flag": flag.Flag}) | ||
| logger.Info("Invalid flag submitted", log15.Ctx{"teamid": team.ID, "ai-agent": flag.AIAgent, "flag": flag.Flag}) |
There was a problem hiding this comment.
all of those will want to use the "source" field instead
|
|
||
| table := tablewriter.NewWriter(os.Stdout) | ||
| table.SetHeader([]string{"ID", "TeamID", "FlagID", "Value", "Submit time", "Notes"}) | ||
| table.SetHeader([]string{"ID", "TeamID", "FlagID", "Value", "Submit time", "AI Agent", "Notes"}) |
|
|
||
| table := tablewriter.NewWriter(os.Stdout) | ||
| table.SetHeader([]string{"ID", "Description", "Value", "Timestamp", "Message", "Notes"}) | ||
| table.SetHeader([]string{"ID", "Description", "Value", "Timestamp", "AI Agent", "Message", "Notes"}) |
| &cli.BoolFlag{ | ||
| Name: "no-ai-autodetect", | ||
| Sources: cli.EnvVars("ASKGOD_DISABLE_AGENT_AUTODETECT"), | ||
| Usage: "Disable automatic AI agent detection", |
| &cli.BoolFlag{ | ||
| Name: "agent", | ||
| Usage: "Flag was found mostly or entirely with an AI agent", | ||
| }, |
There was a problem hiding this comment.
I don't remember this particular CLI library but with spf13/cobra at least, you can make a flag as a tri-state. So being able to check if:
- Flag was passed (value is true)
- Flag was passed with =false (value is false)
- Flag wasn't passed (value is false)
So you'd then use --agent=false as the way to do what your separate --no-ai-autodetect is currently doing
| flag := api.FlagPost{} | ||
| flag.Flag = cmd.Args().Get(0) | ||
| flag.Notes = cmd.String("notes") | ||
| flag.AIAgent = cmd.Bool("agent") |
There was a problem hiding this comment.
Given the previous changes I requested, we can probably track that as just flag.Agent instead of flag.AIAgent so we use more consistent terminology
| FlagID int64 `json:"flag_id" yaml:"flag_id"` | ||
| TeamID int64 `json:"team_id" yaml:"team_id"` | ||
| FlagID int64 `json:"flag_id" yaml:"flag_id"` | ||
| AIAgent bool `json:"ai_agent" yaml:"ai_agent"` |
|
@Res260 is not interested in doing this the way that's been suggested above, closing and taking over |
Add an MCP server for askgod at
<askgod_server_address>/mcp.It has two methods: one to submit flags and one to list the scoreboard.
The list scoreboard method contains a small prompt injection to troll the players.
A new column is added to the
scorestable:source. Its purpose is to track if the flag was submitted using the REST API or using MCP.The
askgod admin list-scoresaudaskgod historycommands were changed to display the source of each flag.Note: This PR was mainly vibecoded using Claude Code, but I reviewed all of it. However, I'm not a golang expert so a thorough review would be appreciated.